Mercurial > hg > rc1
diff vendor/roundcube/plugin-installer/src/Roundcube/Composer/PluginInstaller.php @ 0:1e000243b222
vanilla 1.3.3 distro, I hope
author | Charlie Root |
---|---|
date | Thu, 04 Jan 2018 15:50:29 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/roundcube/plugin-installer/src/Roundcube/Composer/PluginInstaller.php Thu Jan 04 15:50:29 2018 -0500 @@ -0,0 +1,280 @@ +<?php + +namespace Roundcube\Composer; + +use Composer\Installer\LibraryInstaller; +use Composer\Package\Version\VersionParser; +use Composer\Semver\Constraint\Constraint; +use Composer\Package\PackageInterface; +use Composer\Repository\InstalledRepositoryInterface; +use Composer\Util\ProcessExecutor; + +/** + * @category Plugins + * @package PluginInstaller + * @author Till Klampaeckel <till@php.net> + * @author Thomas Bruederli <thomas@roundcube.net> + * @license GPL-3.0+ + * @version GIT: <git_id> + * @link http://github.com/roundcube/plugin-installer + */ +class PluginInstaller extends LibraryInstaller +{ + const INSTALLER_TYPE = 'roundcube-plugin'; + + /** + * {@inheritDoc} + */ + public function getInstallPath(PackageInterface $package) + { + static $vendorDir; + if ($vendorDir === null) { + $vendorDir = $this->getVendorDir(); + } + + return sprintf('%s/%s', $vendorDir, $this->getPluginName($package)); + } + + /** + * {@inheritDoc} + */ + public function install(InstalledRepositoryInterface $repo, PackageInterface $package) + { + $this->rcubeVersionCheck($package); + parent::install($repo, $package); + + // post-install: activate plugin in Roundcube config + $config_file = $this->rcubeConfigFile(); + $plugin_name = $this->getPluginName($package); + $plugin_dir = $this->getVendorDir() . DIRECTORY_SEPARATOR . $plugin_name; + $extra = $package->getExtra(); + $plugin_name = $this->getPluginName($package); + + if (is_writeable($config_file) && php_sapi_name() == 'cli') { + $answer = $this->io->askConfirmation("Do you want to activate the plugin $plugin_name? [N|y] ", false); + if (true === $answer) { + $this->rcubeAlterConfig($plugin_name, true); + } + } + + // copy config.inc.php.dist -> config.inc.php + if (is_file($plugin_dir . DIRECTORY_SEPARATOR . 'config.inc.php.dist') && !is_file($plugin_dir . DIRECTORY_SEPARATOR . 'config.inc.php') && is_writeable($plugin_dir)) { + $this->io->write("<info>Creating plugin config file</info>"); + copy($plugin_dir . DIRECTORY_SEPARATOR . 'config.inc.php.dist', $plugin_dir . DIRECTORY_SEPARATOR . 'config.inc.php'); + } + + // initialize database schema + if (!empty($extra['roundcube']['sql-dir'])) { + if ($sqldir = realpath($plugin_dir . DIRECTORY_SEPARATOR . $extra['roundcube']['sql-dir'])) { + $this->io->write("<info>Running database initialization script for $plugin_name</info>"); + system(getcwd() . "/vendor/bin/rcubeinitdb.sh --package=$plugin_name --dir=$sqldir"); + } + } + + // run post-install script + if (!empty($extra['roundcube']['post-install-script'])) { + $this->rcubeRunScript($extra['roundcube']['post-install-script'], $package); + } + } + + /** + * {@inheritDoc} + */ + public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) + { + $this->rcubeVersionCheck($target); + parent::update($repo, $initial, $target); + + $extra = $target->getExtra(); + + // trigger updatedb.sh + if (!empty($extra['roundcube']['sql-dir'])) { + $plugin_name = $this->getPluginName($target); + $plugin_dir = $this->getVendorDir() . DIRECTORY_SEPARATOR . $plugin_name; + + if ($sqldir = realpath($plugin_dir . DIRECTORY_SEPARATOR . $extra['roundcube']['sql-dir'])) { + $this->io->write("<info>Updating database schema for $plugin_name</info>"); + system(getcwd() . "/bin/updatedb.sh --package=$plugin_name --dir=$sqldir", $res); + } + } + + // run post-update script + if (!empty($extra['roundcube']['post-update-script'])) { + $this->rcubeRunScript($extra['roundcube']['post-update-script'], $target); + } + } + + /** + * {@inheritDoc} + */ + public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) + { + parent::uninstall($repo, $package); + + // post-uninstall: deactivate plugin + $plugin_name = $this->getPluginName($package); + $this->rcubeAlterConfig($plugin_name, false); + + // run post-uninstall script + $extra = $package->getExtra(); + if (!empty($extra['roundcube']['post-uninstall-script'])) { + $this->rcubeRunScript($extra['roundcube']['post-uninstall-script'], $package); + } + } + + /** + * {@inheritDoc} + */ + public function supports($packageType) + { + return $packageType === self::INSTALLER_TYPE; + } + + /** + * Setup vendor directory to one of these two: + * ./plugins + * + * @return string + */ + public function getVendorDir() + { + $pluginDir = getcwd(); + $pluginDir .= '/plugins'; + + return $pluginDir; + } + + /** + * Extract the (valid) plugin name from the package object + */ + private function getPluginName(PackageInterface $package) + { + @list($vendor, $pluginName) = explode('/', $package->getPrettyName()); + + return strtr($pluginName, '-', '_'); + } + + /** + * Check version requirements from the "extra" block of a package + * against the local Roundcube version + */ + private function rcubeVersionCheck($package) + { + $parser = new VersionParser; + + // read rcube version from iniset + $rootdir = getcwd(); + $iniset = @file_get_contents($rootdir . '/program/include/iniset.php'); + if (preg_match('/define\(.RCMAIL_VERSION.,\s*.([0-9.]+[a-z-]*)?/', $iniset, $m)) { + $rcubeVersion = $parser->normalize(str_replace('-git', '.999', $m[1])); + } else { + throw new \Exception("Unable to find a Roundcube installation in $rootdir"); + } + + $extra = $package->getExtra(); + + if (!empty($extra['roundcube'])) { + foreach (array('min-version' => '>=', 'max-version' => '<=') as $key => $operator) { + if (!empty($extra['roundcube'][$key])) { + $version = $parser->normalize(str_replace('-git', '.999', $extra['roundcube'][$key])); + $constraint = new Constraint($operator, $version); + if (!$constraint->versionCompare($rcubeVersion, $version, $operator)) { + throw new \Exception("Version check failed! " . $package->getName() . " requires Roundcube version $operator $version, $rcubeVersion was detected."); + } + } + } + } + } + + /** + * Add or remove the given plugin to the list of active plugins in the Roundcube config. + */ + private function rcubeAlterConfig($plugin_name, $add) + { + $config_file = $this->rcubeConfigFile(); + @include($config_file); + $success = false; + $varname = '$config'; + + if (empty($config) && !empty($rcmail_config)) { + $config = $rcmail_config; + $varname = '$rcmail_config'; + } + + if (is_array($config) && is_writeable($config_file)) { + $config_templ = @file_get_contents($config_file) ?: ''; + $config_plugins = !empty($config['plugins']) ? ((array) $config['plugins']) : array(); + $active_plugins = $config_plugins; + + if ($add && !in_array($plugin_name, $active_plugins)) { + $active_plugins[] = $plugin_name; + } elseif (!$add && ($i = array_search($plugin_name, $active_plugins)) !== false) { + unset($active_plugins[$i]); + } + + if ($active_plugins != $config_plugins) { + $count = 0; + $var_export = "array(\n\t'" . join("',\n\t'", $active_plugins) . "',\n);"; + $new_config = preg_replace( + "/(\\$varname\['plugins'\])\s+=\s+(.+);/Uims", + "\\1 = " . $var_export, + $config_templ, -1, $count); + + // 'plugins' option does not exist yet, add it... + if (!$count) { + $var_txt = "\n{$varname}['plugins'] = $var_export;\n"; + $new_config = str_replace('?>', $var_txt . '?>', $config_templ, $count); + + if (!$count) { + $new_config = $config_templ . $var_txt; + } + } + + $success = file_put_contents($config_file, $new_config); + } + } + + if ($success && php_sapi_name() == 'cli') { + $this->io->write("<info>Updated local config at $config_file</info>"); + } + + return $success; + } + + /** + * Helper method to get an absolute path to the local Roundcube config file + */ + private function rcubeConfigFile() + { + return realpath(getcwd() . '/config/config.inc.php'); + } + + /** + * Run the given script file + */ + private function rcubeRunScript($script, PackageInterface $package) + { + $plugin_name = $this->getPluginName($package); + $plugin_dir = $this->getVendorDir() . DIRECTORY_SEPARATOR . $plugin_name; + + // check for executable shell script + if (($scriptfile = realpath($plugin_dir . DIRECTORY_SEPARATOR . $script)) && is_executable($scriptfile)) { + $script = $scriptfile; + } + + // run PHP script in Roundcube context + if ($scriptfile && preg_match('/\.php$/', $scriptfile)) { + $incdir = realpath(getcwd() . '/program/include'); + include_once($incdir . '/iniset.php'); + include($scriptfile); + } + // attempt to execute the given string as shell commands + else { + $process = new ProcessExecutor($this->io); + $exitCode = $process->execute($script, null, $plugin_dir); + if ($exitCode !== 0) { + throw new \RuntimeException('Error executing script: '. $process->getErrorOutput(), $exitCode); + } + } + } +}