Allow symlinking when installing packages from the source repository.
authorGunnar Wrobel <p@rdus.de>
Fri, 29 Oct 2010 09:38:41 +0000 (11:38 +0200)
committerGunnar Wrobel <p@rdus.de>
Fri, 29 Oct 2010 09:38:41 +0000 (11:38 +0200)
Now the --install option of components should be capable of completely
installing the horde stack starting with the new package.xml at
horde/package.xml down to all PEAR dependencies. Code from the
repository can be symlinked for dev mode. So this is getting nearer
to a replacement for framework/bin/install_{framework,dev}.

php horde/components/bin/horde-components --install=/srv/www/h4/.pearrc --symlink horde/horde

Currently the "Horde" role does not work yet and I assume there are
quite a few other corner cases/bugs that I will need to weed out.

components/TODO
components/lib/Components/Helper/InstallationRun.php
components/lib/Components/Module/Installer.php
components/lib/Components/Pear/InstallLocation.php
components/lib/Components/Pear/Package.php
components/lib/Components/Runner/Installer.php

index 52a72db..922d83c 100644 (file)
@@ -4,26 +4,20 @@
 
  - Document usage
 
- - Add module for generating component documentation.
-
- - Allow linking files during the installation.
-
  - Allow filtering (see http://github.com/horde/horde/commit/404e8d1ea7c0bf99373aec2ce7f2534a442149b3)
    Potentially check with git if the file is relevant or not.
 
  - Fix dependency listing with the --optional=yes/no flag
 
- - Allow optional installation of PECL packages
+ - Allow downloading documentation from the wiki.
+
+ - Add module for generating component documentation.
 
  - Add a commit module that automatically adds a changelog entry in
    the notes section of the package.xml
 
  - Add a release helper module.
 
- - Allow downloading documentation from the wiki.
-
- - Maybe prefix the job names of packages from the framework with Horde_
-
  - Allow absolute/relative paths as arguments
 
  - WWW frontend
index eca2d05..24a3014 100644 (file)
@@ -51,6 +51,13 @@ class Components_Helper_InstallationRun
     private $_output;
 
     /**
+     * The options for this run.
+     *
+     * @param array
+     */
+    private $_options;
+
+    /**
      * The list of channels already installed.
      *
      * @var array
@@ -270,9 +277,15 @@ class Components_Helper_InstallationRun
     private function _installHordePackageOnce($package_file, $reason = '')
     {
         if (empty($this->_options['pretend'])) {
-            $this->_environment->addPackageFromSource(
-                $package_file, $reason
-            );
+            if (empty($this->_options['symlink'])) {
+                $this->_environment->addPackageFromSource(
+                    $package_file, $reason
+                );
+            } else {
+                $this->_environment->linkPackageFromSource(
+                    $package_file, $reason
+                );
+            }
         } else {
             $this->_output->ok(
                 sprintf(
index a8e4af1..760c15e 100644 (file)
@@ -110,6 +110,22 @@ extends Components_Module_Base
                     'help'   => 'Just indicate what would be installed.',
                 )
             ),
+            new Horde_Argv_Option(
+                '-s',
+                '--symlink',
+                array(
+                    'action' => 'store_true',
+                    'help'   => 'Symlink the files from the source repository rather than copying them to the install location. This is intended for the development mode where you want to have your edits to have a direct effect on your installation while still retaining the possibility of commiting to your repository.',
+                )
+            ),
+            new Horde_Argv_Option(
+                '-H',
+                '--horde-dir',
+                array(
+                    'action' => 'store',
+                    'help'   => 'The location of the horde installation directory. The default will be the INSTALL/horde directory',
+                )
+            ),
         );
     }
 
index 7eca2d6..6efd107 100644 (file)
@@ -370,6 +370,86 @@ class Components_Pear_InstallLocation
     }
 
     /**
+     * Add a package based on a source directory.
+     *
+     * @param string $package The path to the package.xml in the source directory.
+     * @param string $reason  Optional reason for adding the package.
+     *
+     * @return NULL
+     */
+    public function linkPackageFromSource($package, $reason = '')
+    {
+        $this->_output->ok(
+            sprintf(
+                'About to symlink package %s%s',
+                $package,
+                $reason
+            )
+        );
+
+        $hordeDir = $this->getPearConfig()->get('horde_dir');
+        $destDir = $this->getPearConfig()->get('php_dir');
+
+        ob_start();
+        $pkg = $this->_factory->createPackageForEnvironment($package, $this);
+        $dir = dirname($package);
+        foreach ($pkg->getInstallationFilelist() as $file) {
+            $orig = realpath($dir . '/' . $file['attribs']['name']);
+            if (empty($orig)) {
+                $this->_output->warn('Install file does not seem to exist: ' . $dir . '/' . $file['attribs']['name']);
+                continue;
+            }
+
+            switch ($file['attribs']['role']) {
+            case 'horde':
+                if (isset($file['attribs']['install-as'])) {
+                    $dest = $hordeDir . '/' . $file['attribs']['install-as'];
+                } else {
+                    $this->_output->warn('Could not determine install directory (role "horde") for ' . $hordeDir);
+                    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 (file_exists($dest)) {
+                    @unlink($dest);
+                } elseif (!file_exists(dirname($dest))) {
+                    @mkdir(dirname($dest), 0777, true);
+                }
+
+                print 'SYMLINK: ' . $orig . ' -> ' . $dest . "\n";
+                if (!symlink($orig, $dest)) {
+                    $this->_output->warn('Could not link ' . $orig . '.');
+                }
+            }
+        }
+        $this->_output->pear(ob_get_clean());
+
+        $this->_output->ok(
+            sprintf(
+                'Successfully symlinked package %s%s',
+                $package,
+                $reason
+            )
+        );
+    }
+
+    /**
      * Add an external dependency based on a package name or package tarball.
      *
      * @param Components_Pear_Dependency $dependency The package dependency.
index 8eba628..4454f8d 100644 (file)
@@ -279,6 +279,16 @@ class Components_Pear_Package
     }
 
     /**
+     * Return the list of files that should be installed for this package.
+     *
+     * @return array The file list.
+     */
+    public function getInstallationFilelist()
+    {
+        return $this->_getPackageFile()->getInstallationFilelist();
+    }
+
+    /**
      * Update the content listing of the provided package.
      *
      * @param PEAR_PackageFileManager2 $package The package to update.
index 6296aaa..a490ffe 100644 (file)
@@ -76,12 +76,16 @@ class Components_Runner_Installer
         if (!$environment) {
             $environment = $options['install'];
         }
+        if (empty($options['horde_dir'])) {
+            $options['horde_dir'] = $environment . DIRECTORY_SEPARATOR . 'horde';
+        }
         $arguments = $this->_config->getArguments();
         $tree = $this->_factory
             ->createTreeHelper(
                 $environment, realpath($arguments[0]), $options
             );
         $tree->getEnvironment()->provideChannel('pear.horde.org');
+        $tree->getEnvironment()->getPearConfig()->set('horde_dir', $options['horde_dir'], 'user', 'pear.horde.org');
         $tree->installTreeInEnvironment(
             realpath($arguments[0]) . DIRECTORY_SEPARATOR . 'package.xml',
             $this->_output,