--- /dev/null
+<?php
+/**
+ * Horde_Element_Module_Installer:: installs a Horde element including
+ * its dependencies.
+ *
+ * PHP version 5
+ *
+ * @category Horde
+ * @package Element
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Element
+ */
+
+/**
+ * Horde_Element_Module_Installer:: installs a Horde element including
+ * its dependencies.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @category Horde
+ * @package Element
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Element
+ */
+class Horde_Element_Module_Installer
+implements Horde_Element_Module
+{
+ public function getOptionGroupTitle()
+ {
+ return 'Installer';
+ }
+
+ public function getOptionGroupDescription()
+ {
+ return 'This module installs a Horde element including its dependencies.';
+ }
+
+ public function getOptionGroupOptions()
+ {
+ return array(
+ new Horde_Argv_Option(
+ '-i',
+ '--install',
+ array(
+ 'action' => 'store',
+ 'help' => 'install the element into the specified absolute INSTALL location'
+ )
+ ),
+ );
+ }
+
+ public function handle(Horde_Element_Config $config)
+ {
+ $options = $config->getOptions();
+ if (!empty($options['install'])) {
+ $this->run($config);
+ }
+ }
+
+ public function run(Horde_Element_Config $config)
+ {
+ $options = $config->getOptions();
+
+ $pear = new PEAR();
+ $pear->setErrorHandling(PEAR_ERROR_DIE);
+
+ $pearrc = $options['install'] . DIRECTORY_SEPARATOR . '.pearrc';
+ $command_config = new PEAR_Command_Config(new PEAR_Frontend_CLI(), new stdClass);
+ $command_config->doConfigCreate(
+ 'config-create', array(), array($options['install'], $pearrc)
+ );
+
+ $pear_config = new PEAR_Config($pearrc);
+ $GLOBALS['_PEAR_Config_instance'] = $pear_config;
+
+ $channel = new PEAR_Command_Channels(
+ new PEAR_Frontend_CLI(),
+ $pear_config
+ );
+ $channel->doDiscover('channel-discover', array(), array('pear.horde.org'));
+ $channel->doDiscover('channel-discover', array(), array('pear.phpunit.de'));
+
+ $installer = new PEAR_Command_Install(
+ new PEAR_Frontend_CLI(),
+ $pear_config
+ );
+
+ $arguments = $config->getArguments();
+ $element = basename(realpath($arguments[0]));
+ $root_path = dirname(realpath($arguments[0]));
+
+ $this->_installHordeDependency(
+ $installer,
+ $pear_config,
+ $root_path,
+ $element
+ );
+ }
+
+ /**
+ * Install a Horde dependency from the current tree (the framework).
+ *
+ * @param PEAR_Command_Install $installer Installs the dependency.
+ * @param PEAR_Config $pear_config The configuration of the PEAR
+ * environment in which the
+ * dependency will be installed.
+ * @param string $root_path Root path to the Horde framework.
+ * @param string $dependency Package name of the dependency.
+ */
+ private function _installHordeDependency(
+ PEAR_Command_Install $installer,
+ PEAR_Config $pear_config,
+ $root_path,
+ $dependency
+ ) {
+ $package_file = $root_path . DIRECTORY_SEPARATOR
+ . $dependency . DIRECTORY_SEPARATOR . 'package.xml';
+
+ $parser = new PEAR_PackageFile_Parser_v2();
+ $parser->setConfig($pear_config);
+ $pkg = $parser->parse(file_get_contents($package_file), $package_file);
+
+ $dependencies = $pkg->getDeps();
+ foreach ($dependencies as $dependency) {
+ if (isset($dependency['channel']) && $dependency['channel'] != 'pear.horde.org') {
+ $installer->doInstall(
+ 'install',
+ array(
+ 'force' => true,
+ 'channel' => $dependency['channel'],
+ ),
+ array($dependency['name'])
+ );
+ } else if (isset($dependency['channel'])) {
+ $this->_installHordeDependency(
+ $installer,
+ $pear_config,
+ $root_path,
+ $dependency['name']
+ );
+ }
+ }
+ $installer->doInstall(
+ 'install',
+ array('nodeps' => true),
+ array($package_file)
+ );
+ }
+}
)
);
+ if ($package instanceOf PEAR_Error) {
+ throw new Horde_Element_Exception($package->getMessage());
+ }
$package->generateContents();
/**
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($module_directory)) as $file) {
if ($file->isFile() && preg_match('/.php$/', $file->getFilename())) {
$class = $base . preg_replace("/^(.*)\.php/", '\\1', $file->getFilename());
- if (!class_exists($class)) {
- require $file->getPathname();
- }
$this->_modules[$class] = new $class();
}
}
<email>jan@horde.org</email>
<active>yes</active>
</lead>
- <date>2010-07-05</date>
- <time>05:44:10</time>
+ <date>2010-08-22</date>
+ <time>21:12:03</time>
<version>
<release>0.0.1</release>
<api>0.0.1</api>
<file name="Cli.php" role="php" />
</dir> <!-- /lib/Horde/Element/Config -->
<dir name="Module">
+ <file name="Installer.php" role="php" />
<file name="PearPackageXml.php" role="php" />
</dir> <!-- /lib/Horde/Element/Module -->
<file name="Autoloader.php" role="php" />
<dependencies>
<required>
<php>
- <min>5.0.0</min>
+ <min>5.2.1</min>
</php>
<pearinstaller>
<min>1.7.0</min>
</pearinstaller>
<package>
+ <name>PEAR_PackageFileManager2</name>
+ <channel>pear.php.net</channel>
+ </package>
+ <package>
<name>Autoloader</name>
<channel>pear.horde.org</channel>
</package>
<install as="Horde/Element/Module.php" name="lib/Horde/Element/Module.php" />
<install as="Horde/Element/Modules.php" name="lib/Horde/Element/Modules.php" />
<install as="Horde/Element/Config/Cli.php" name="lib/Horde/Element/Config/Cli.php" />
+ <install as="Horde/Element/Module/Installer.php" name="lib/Horde/Element/Module/Installer.php" />
<install as="Horde/Element/Module/PearPackageXml.php" name="lib/Horde/Element/Module/PearPackageXml.php" />
<install as="horde-element" name="script/horde-element.php" />
<install as="Horde/Element/AllTests.php" name="test/Horde/Element/AllTests.php" />
<release>alpha</release>
<api>alpha</api>
</stability>
- <date>2010-07-05</date>
+ <date>2010-08-22</date>
<license uri="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">LGPL</license>
<notes>
* Initial release
->when('calling the package with the help option')
->then('the help will contain the "u" option.');
}
+
+ /**
+ * @scenario
+ */
+ public function theThePOptionProvidesAnUpdatedPackageXml()
+ {
+ $this->given('the default Element setup')
+ ->when('calling the package with the packagexml option and a Horde element')
+ ->then('the new package.xml of the Horde element will be printed.');
+ }
+
+ /**
+ * @todo Test (and fix) the reactions to three more scenarios:
+ * - invalid XML in the package.xml (e.g. tag missing)
+ * - empty file list
+ * - file list with just one entry.
+ *
+ * All three scenarios yield errors which are still hard to
+ * understand.
+ */
+
+ /**
+ * @scenario
+ */
+ public function theInstallerModuleAddsTheIOptionInTheHelpOutput()
+ {
+ $this->given('the default Element setup')
+ ->when('calling the package with the help option')
+ ->then('the help will contain the "i" option.');
+ }
+
+ /**
+ * @scenario
+ */
+ public function theTheIOptionInstallsThePackageFromTheCurrentTree()
+ {
+ $this->given('the default Element setup')
+ ->when('calling the package with the install option and a Horde element')
+ ->then('a new PEAR configuration file will be installed')
+ ->and('the PEAR package will be installed')
+ ->and('the non-Horde dependencies of the Horde element will get installed from the network.')
+ ->and('the Horde dependencies of the Horde element will get installed from the current tree.')
+ ->and('the Horde element will be installed');
+ }
}
\ No newline at end of file
class Horde_Element_StoryTestCase
extends PHPUnit_Extensions_Story_TestCase
{
+ public function tearDown()
+ {
+ if (!empty($this->_temp_dir)) {
+ $this->_rrmdir($this->_temp_dir);
+ }
+ }
+
/**
* Handle a "given" step.
*
$_SERVER['argv'] = array(
'horde-element',
'--help',
- dirname(__FILE__) . '/fixture'
+ dirname(__FILE__) . '/fixture/empty'
+ );
+ ob_start();
+ $parameters = array();
+ $parameters['cli']['parser']['class'] = 'Horde_Element_Stub_Parser';
+ Horde_Element::main($parameters);
+ $world['output'] = ob_get_contents();
+ ob_end_clean();
+ break;
+ case 'calling the package with the packagexml option and a Horde element':
+ $_SERVER['argv'] = array(
+ 'horde-element',
+ '--packagexml',
+ dirname(__FILE__) . '/fixture/simple'
+ );
+ ob_start();
+ $parameters = array();
+ $parameters['cli']['parser']['class'] = 'Horde_Element_Stub_Parser';
+ $old_errorreporting = error_reporting(E_ALL & ~E_STRICT);
+ Horde_Element::main($parameters);
+ error_reporting($old_errorreporting);
+ $world['output'] = ob_get_contents();
+ ob_end_clean();
+ break;
+ case 'calling the package with the install option and a Horde element':
+ $_SERVER['argv'] = array(
+ 'horde-element',
+ '--install=' . $this->_getTemporaryDirectory(),
+ dirname(__FILE__) . '/../../../'
);
ob_start();
$parameters = array();
$parameters['cli']['parser']['class'] = 'Horde_Element_Stub_Parser';
+ $old_errorreporting = error_reporting(E_ALL & ~E_STRICT);
Horde_Element::main($parameters);
+ error_reporting($old_errorreporting);
$world['output'] = ob_get_contents();
ob_end_clean();
break;
$world['output']
);
break;
+ case 'the help will contain the "i" option.':
+ $this->assertRegExp(
+ '/-i\s*INSTALL,\s*--install=INSTALL/',
+ $world['output']
+ );
+ break;
+ case 'the new package.xml of the Horde element will be printed.':
+ $this->assertRegExp(
+ '/<file name="New.php" role="php" \/>/',
+ $world['output']
+ );
+ break;
+ case 'a new PEAR configuration file will be installed':
+ $this->assertTrue(
+ file_exists($this->_temp_dir . DIRECTORY_SEPARATOR . '.pearrc')
+ );
+ break;
+ case 'the PEAR package will be installed':
+ $this->assertTrue(
+ file_exists(
+ $this->_temp_dir . DIRECTORY_SEPARATOR
+ . 'pear' . DIRECTORY_SEPARATOR
+ . 'php' . DIRECTORY_SEPARATOR
+ . 'PEAR.php'
+ )
+ );
+ break;
+ case 'the non-Horde dependencies of the Horde element will get installed from the network.':
+ var_dump($world['output']);
+ $this->assertTrue(
+ file_exists(
+ $this->_temp_dir . DIRECTORY_SEPARATOR
+ . 'pear' . DIRECTORY_SEPARATOR
+ . 'php' . DIRECTORY_SEPARATOR
+ . 'PEAR' . DIRECTORY_SEPARATOR
+ . 'PackageFileManager2.php'
+ )
+ );
+ break;
+ case 'the Horde dependencies of the Horde element will get installed from the current tree.':
+ $this->assertTrue(
+ file_exists(
+ $this->_temp_dir . DIRECTORY_SEPARATOR
+ . 'pear' . DIRECTORY_SEPARATOR
+ . 'php' . DIRECTORY_SEPARATOR
+ . 'Horde' . DIRECTORY_SEPARATOR
+ . 'Autoloader.php'
+ )
+ );
+ break;
+ case 'the Horde element will be installed':
+ $this->assertTrue(
+ file_exists(
+ $this->_temp_dir . DIRECTORY_SEPARATOR
+ . 'pear' . DIRECTORY_SEPARATOR
+ . 'php' . DIRECTORY_SEPARATOR
+ . 'Horde' . DIRECTORY_SEPARATOR
+ . 'Element.php'
+ )
+ );
+ break;
default:
return $this->notImplemented($action);
}
}
+ private function _getTemporaryDirectory()
+ {
+ $this->_temp_dir = sys_get_temp_dir() . DIRECTORY_SEPARATOR
+ . 'Horde_Element_' . mt_rand();
+ mkdir($this->_temp_dir);
+ return $this->_temp_dir;
+ }
+
+ private function _rrmdir($dir)
+ {
+ if (is_dir($dir)) {
+ $objects = scandir($dir);
+ foreach ($objects as $object) {
+ if ($object != '.' && $object != '..') {
+ if (filetype($dir . DIRECTORY_SEPARATOR . $object) == 'dir') {
+ $this->_rrmdir($dir . DIRECTORY_SEPARATOR . $object);
+ } else {
+ unlink($dir . DIRECTORY_SEPARATOR . $object);
+ }
+ }
+ }
+ reset($objects);
+ rmdir($dir);
+ }
+ }
}
\ No newline at end of file
--- /dev/null
+<?php
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.9.0" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
+ <name>Fixture</name>
+ <channel>pear.horde.org</channel>
+ <summary>Test fixture.</summary>
+ <description>A dummy package.xml used for testing the Horde_Element package.</description>
+ <lead>
+ <name>Gunnar Wrobel</name>
+ <user>wrobel</user>
+ <email>p@rdus.de</email>
+ <active>yes</active>
+ </lead>
+ <date>2010-08-22</date>
+ <time>21:12:03</time>
+ <version>
+ <release>0.0.1</release>
+ <api>0.0.1</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <license uri="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">LGPL</license>
+ <notes>
+* Initial release
+ </notes>
+ <contents>
+ <dir baseinstalldir="/" name="/">
+ <dir name="lib">
+ <file name="Old.php" role="php" />
+ </dir> <!-- /lib -->
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.0.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.7.0</min>
+ </pearinstaller>
+ </required>
+ </dependencies>
+ <phprelease>
+ <filelist>
+ <install as="Old.php" name="lib/Old.php" />
+ </filelist>
+ </phprelease>
+ <changelog>
+ <release>
+ <version>
+ <release>0.0.1</release>
+ <api>0.0.1</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <date>2010-08-22</date>
+ <license uri="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">LGPL</license>
+ <notes>
+* Initial release
+ </notes>
+ </release>
+ </changelog>
+</package>