Extract the tree handling into a separate helper that should later also allow to...
authorGunnar Wrobel <p@rdus.de>
Wed, 13 Oct 2010 14:11:22 +0000 (16:11 +0200)
committerGunnar Wrobel <p@rdus.de>
Wed, 13 Oct 2010 19:14:45 +0000 (21:14 +0200)
components/lib/Components/Helper/InstallationRun.php [new file with mode: 0644]
components/lib/Components/Helper/Tree.php [new file with mode: 0644]
components/lib/Components/Helper/Tree/Element.php [new file with mode: 0644]
components/lib/Components/Module/Installer.php
components/lib/Components/Pear/Factory.php
components/lib/Components/Runner/Installer.php
components/test/Components/StoryTestCase.php

diff --git a/components/lib/Components/Helper/InstallationRun.php b/components/lib/Components/Helper/InstallationRun.php
new file mode 100644 (file)
index 0000000..5f833be
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+/**
+ * Components_Helper_InstallationRun:: provides a utility that records what has
+ * already happened during an installation run.
+ *
+ * PHP version 5
+ *
+ * @category Horde
+ * @package  Components
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @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 <wrobel@pardus.de>
+ * @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 (file)
index 0000000..ac9d510
--- /dev/null
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Components_Helper_Tree:: handles a tree of dependencies and takes the Horde
+ * component layout into account.
+ *
+ * PHP version 5
+ *
+ * @category Horde
+ * @package  Components
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @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 <wrobel@pardus.de>
+ * @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 (file)
index 0000000..989a494
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Components_Helper_Tree_Element:: provides utility methods for a single
+ * element of the tree.
+ *
+ * PHP version 5
+ *
+ * @category Horde
+ * @package  Components
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @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 <wrobel@pardus.de>
+ * @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
index 1e51eb5..011d366 100644 (file)
@@ -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(
index 04e0f9e..918d0ca 100644 (file)
@@ -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.
index 48c1c31..065bb69 100644 (file)
@@ -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;
     }
 }
index 39929a1..6a1bf25 100644 (file)
@@ -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();