From 4efe096dee67b13b1e316e8784242ed0482cb6b9 Mon Sep 17 00:00:00 2001 From: Gunnar Wrobel Date: Wed, 13 Oct 2010 16:11:22 +0200 Subject: [PATCH] Extract the tree handling into a separate helper that should later also allow to get a quick overview on package dependencies. --- .../lib/Components/Helper/InstallationRun.php | 122 +++++++++++++++++++ components/lib/Components/Helper/Tree.php | 131 +++++++++++++++++++++ components/lib/Components/Helper/Tree/Element.php | 94 +++++++++++++++ components/lib/Components/Module/Installer.php | 2 +- components/lib/Components/Pear/Factory.php | 20 ++++ components/lib/Components/Runner/Installer.php | 78 ++---------- components/test/Components/StoryTestCase.php | 2 +- 7 files changed, 381 insertions(+), 68 deletions(-) create mode 100644 components/lib/Components/Helper/InstallationRun.php create mode 100644 components/lib/Components/Helper/Tree.php create mode 100644 components/lib/Components/Helper/Tree/Element.php diff --git a/components/lib/Components/Helper/InstallationRun.php b/components/lib/Components/Helper/InstallationRun.php new file mode 100644 index 000000000..5f833be7f --- /dev/null +++ b/components/lib/Components/Helper/InstallationRun.php @@ -0,0 +1,122 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Components + */ + +/** + * Components_Helper_InstallationRun:: provides a utility that records what has + * already happened during an installation run. + * + * 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 Components + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Components + */ +class Components_Helper_InstallationRun +{ + /** + * The environment we establish the tree for. + * + * @var Components_Pear_InstallLocation + */ + private $_environment; + + /** + * The list of channels already installed. + * + * @var array + */ + private $_installed_channels = array(); + + /** + * The list of packages already installed. + * + * @var array + */ + private $_installed_packages = array(); + + /** + * Constructor. + * + * @param Components_Pear_InstallLocation $environment The environment we + * establish the tree for. + */ + public function __construct( + Components_Pear_InstallLocation $environment + ) { + $this->_environment = $environment; + } + + /** + * Ensure that the listed channels are available within the installation + * environment. The channels are only going to be installed once during the + * installation run represented by this instance. + * + * @return NULL + */ + public function installChannelsOnce(array $channels) + { + foreach ($channels as $channel) { + if (!in_array($channel, $this->_installed_channels)) { + $this->_environment->provideChannel($channel); + $this->_installed_channels[] = $channel; + } + } + } + + /** + * Ensure that the external package is available within the installation + * environment. The package is only going to be installed once during the + * installation run represented by this instance. + * + * @param string $package The package that should be installed. + * @param string $channel The channel of the package. + * + * @return NULL + */ + public function installExternalPackageOnce($channel, $package) + { + $key = $channel . '/' . $package; + if (!in_array($key, $this->_installed_packages)) { + $this->_environment->addPackageFromPackage( + $channel, $package + ); + $this->_installed_packages[] = $key; + } + } + + /** + * Ensure that the horde package is available within the installation + * environment. The package is only going to be installed once during the + * installation run represented by this instance. + * + * @param string $package_file The package file indicating which Horde + * source package should be installed. + * + * @return NULL + */ + public function installHordePackageOnce($package_file) + { + if (!in_array($package_file, $this->_installed_packages)) { + $this->_environment->addPackageFromSource( + $package_file + ); + $this->_installed_packages[] = $package_file; + } + } +} \ No newline at end of file diff --git a/components/lib/Components/Helper/Tree.php b/components/lib/Components/Helper/Tree.php new file mode 100644 index 000000000..ac9d510f7 --- /dev/null +++ b/components/lib/Components/Helper/Tree.php @@ -0,0 +1,131 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Components + */ + +/** + * Components_Helper_Tree:: handles a tree of dependencies and takes the Horde + * component layout into account. + * + * 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 Components + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Components + */ +class Components_Helper_Tree +{ + /** + * The factory for PEAR dependencies. + * + * @var Components_Pear_Factory + */ + private $_factory; + + /** + * The environment we establish the tree for. + * + * @var Components_Pear_InstallLocation + */ + private $_environment; + + /** + * The root path for the Horde package hierarchy. + * + * @var string + */ + private $_root_path; + + /** + * Constructor. + * + * @param Components_Pear_Factory $factory The factory for PEAR + * dependencies. + * @param Components_Pear_InstallLocation $environment The PEAR environment. + * @param string $root_path The basic root path for + * Horde packages. + * + */ + public function __construct( + Components_Pear_Factory $factory, + Components_Pear_InstallLocation $environment, + $root_path + ) { + $this->_factory = $factory; + $this->_environment = $environment; + $this->_root_path = $root_path; + } + + /** + * Install the tree of packages into the specified environment. + * + * @param string $package_file Path to the package file + * representing the element + * at the root of the + * dependency tree. + * @return NULL + */ + public function installTreeInEnvironment($package_file) { + $this->_getHordeChildElement($package_file) + ->installInTree( + new Components_Helper_InstallationRun($this->_environment) + ); + } + + /** + * Get the children for an element. + * + * @param array $dependencies The dependencies of a package to be + * transformed in elements. + * @return array The list of children elements. + */ + public function getChildren(array $dependencies) + { + $children = array(); + foreach ($dependencies as $dependency) { + $package_file = $this->_root_path . DIRECTORY_SEPARATOR + . $dependency['name'] . DIRECTORY_SEPARATOR . 'package.xml'; + if (!file_exists($package_file)) { + $package_file = $this->_root_path . DIRECTORY_SEPARATOR + . 'framework' . DIRECTORY_SEPARATOR . $dependency['name'] + . DIRECTORY_SEPARATOR . 'package.xml'; + } + $children[] = $this->_getHordeChildElement($package_file); + } + return $children; + } + + /** + * Return a Horde child element. + * + * @param string $package_file Path to the package + * file representing the + * element at the root + * of the dependency tree. + * @return NULL + */ + private function _getHordeChildElement($package_file) + { + return new Components_Helper_Tree_Element( + $this->_factory->createPackageForEnvironment( + $package_file, $this->_environment + ), + $package_file, + $this + ); + } +} \ No newline at end of file diff --git a/components/lib/Components/Helper/Tree/Element.php b/components/lib/Components/Helper/Tree/Element.php new file mode 100644 index 000000000..989a494af --- /dev/null +++ b/components/lib/Components/Helper/Tree/Element.php @@ -0,0 +1,94 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Components + */ + +/** + * Components_Helper_Tree_Element:: provides utility methods for a single + * element of the tree. + * + * 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 Components + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Components + */ +class Components_Helper_Tree_Element +{ + /** + * The package represented by this element. + * + * @var Components_Pear_Package + */ + private $_package; + + /** + * The path to the package file defining this element. + * + * @var string + */ + private $_package_file; + + /** + * The parent tree for this child. + * + * @var Components_Helper_Tree + */ + private $_tree; + + /** + * Constructor. + * + * @param Components_Pear_Package $package The root of the dependency tree. + * @param string $package_file The path to the package file. + * @param Components_Helper_Tree $tree The parent tree for this child. + */ + public function __construct( + Components_Pear_Package $package, + $package_file, + Components_Helper_Tree $tree + ) { + $this->_package = $package; + $this->_package_file = $package_file; + $this->_tree = $tree; + } + + /** + * Install the tree of packages into the environment. + * + * @param Components_Helper_InstallationRun $run The current installation run. + * + * @return NULL + */ + public function installInTree(Components_Helper_InstallationRun $run) + { + $run->installChannelsOnce($this->_package->listAllRequiredChannels()); + foreach ($this->_package->listAllExternalDependencies() as $dependency) { + $run->installExternalPackageOnce( + $dependency['channel'], $dependency['name'] + ); + } + foreach ( + $this->_tree->getChildren( + $this->_package->listAllHordeDependencies() + ) as $child + ) { + $child->installInTree($run); + } + $run->installHordePackageOnce($this->_package_file); + } +} \ No newline at end of file diff --git a/components/lib/Components/Module/Installer.php b/components/lib/Components/Module/Installer.php index 1e51eb5cf..011d3666b 100644 --- a/components/lib/Components/Module/Installer.php +++ b/components/lib/Components/Module/Installer.php @@ -63,7 +63,7 @@ extends Components_Module_Base '--install', array( 'action' => 'store', - 'help' => 'Install the element into the specified absolute INSTALL location' + 'help' => 'Install the element into the PEAR environment represented by this PEAR configuration file' ) ), new Horde_Argv_Option( diff --git a/components/lib/Components/Pear/Factory.php b/components/lib/Components/Pear/Factory.php index 04e0f9ed7..918d0ca75 100644 --- a/components/lib/Components/Pear/Factory.php +++ b/components/lib/Components/Pear/Factory.php @@ -114,6 +114,26 @@ class Components_Pear_Factory } /** + * Create a tree helper for a specific PEAR environment.. + * + * @param string $config_file The path to the configuration file. + * @param string $root_path The basic root path for Horde packages. + * @param array $options The application options + * + * @return Components_Helper_Tree The tree helper. + */ + public function createTreeHelper($config_file, $root_path, array $options) + { + $environment = $this->_dependencies->createInstance('Components_Pear_InstallLocation'); + $environment->setLocation( + dirname($config_file), + basename($config_file) + ); + $environment->setResourceDirectories($options); + return new Components_Helper_Tree($this, $environment, $root_path); + } + + /** * Return the PEAR Package representation. * * @param string $package_xml_path Path to the package.xml file. diff --git a/components/lib/Components/Runner/Installer.php b/components/lib/Components/Runner/Installer.php index 48c1c3103..065bb69e8 100644 --- a/components/lib/Components/Runner/Installer.php +++ b/components/lib/Components/Runner/Installer.php @@ -39,9 +39,9 @@ class Components_Runner_Installer private $_config; /** - * The factory for PEAR handlers. + * The factory for PEAR dependencies. * - * @var Components_Factory + * @var Components_Pear_Factory */ private $_factory; @@ -50,8 +50,8 @@ class Components_Runner_Installer * * @param Components_Config $config The configuration for the current * job. - * @param Components_Pear_Factory $factory Generator for all required PEAR - * components. + * @param Components_Pear_Factory $factory The factory for PEAR + * dependencies. */ public function __construct( Components_Config $config, @@ -64,70 +64,16 @@ class Components_Runner_Installer public function run() { $options = $this->_config->getOptions(); - $location = realpath($options['install']); - if (!$location) { - $location = $options['install']; + $environment = realpath($options['install']); + if (!$environment) { + $environment = $options['install']; } - $environment = $this->_factory - ->createInstallLocation($location . DIRECTORY_SEPARATOR . '.pearrc'); - $environment->setResourceDirectories($options); - $pear_config = $environment->getPearConfig(); - $arguments = $this->_config->getArguments(); - $element = basename(realpath($arguments[0])); - $root_path = dirname(realpath($arguments[0])); - - $this->_run = array(); - - $this->_installHordeDependency( - $environment, - $root_path, - $element - ); - } - - /** - * Install a Horde dependency from the current tree (the framework). - * - * @param string $root_path Root path to the Horde framework. - * @param string $dependency Package name of the dependency. - */ - private function _installHordeDependency($environment, $root_path, $dependency) - { - $package_file = $root_path . DIRECTORY_SEPARATOR - . $dependency . DIRECTORY_SEPARATOR . 'package.xml'; - if (!file_exists($package_file)) { - $package_file = $root_path . DIRECTORY_SEPARATOR . 'framework' . DIRECTORY_SEPARATOR - . $dependency . DIRECTORY_SEPARATOR . 'package.xml'; - } - - $pkg = $this->_factory->createPackageForEnvironment($package_file, $environment); - $environment->provideChannels($pkg->listAllRequiredChannels()); - foreach ($pkg->listAllExternalDependencies() as $dependency) { - $key = $dependency['channel'] . '/' . $dependency['name']; - if (in_array($key, $this->_run)) { - continue; - } - $environment->addPackageFromPackage( - $dependency['channel'], $dependency['name'] + $this->_factory + ->createTreeHelper( + $environment, dirname(realpath($arguments[0])), $options + )->installTreeInEnvironment( + realpath($arguments[0]) . DIRECTORY_SEPARATOR . 'package.xml' ); - $this->_run[] = $key; - } - foreach ($pkg->listAllHordeDependencies() as $dependency) { - $key = $dependency['channel'] . '/' . $dependency['name']; - if (in_array($key, $this->_run)) { - continue; - } - $this->_run[] = $key; - $this->_installHordeDependency($environment, $root_path, $dependency['name']); - } - if (in_array($package_file, $this->_run)) { - return; - } - - $environment->addPackageFromSource( - $package_file - ); - $this->_run[] = $package_file; } } diff --git a/components/test/Components/StoryTestCase.php b/components/test/Components/StoryTestCase.php index 39929a133..6a1bf25ad 100644 --- a/components/test/Components/StoryTestCase.php +++ b/components/test/Components/StoryTestCase.php @@ -177,7 +177,7 @@ extends PHPUnit_Extensions_Story_TestCase 'horde-components', '--channelxmlpath=' . dirname(__FILE__) . '/fixture/channels', '--sourcepath=' . dirname(__FILE__) . '/fixture/packages', - '--install=' . $this->_getTemporaryDirectory(), + '--install=' . $this->_getTemporaryDirectory() . DIRECTORY_SEPARATOR . '.pearrc', dirname(__FILE__) . '/fixture/framework/Install' ); $world['output'] = $this->_callUnstrictComponents(); -- 2.11.0