Skip to content

Commit

Permalink
Version 1.0.0:
Browse files Browse the repository at this point in the history
Changed: Assume 'yes' in non-interactive mode.
Fixed: Deprecation Notice: The Composer\Package\LinkConstraint\VersionConstraint class is deprecated...
  • Loading branch information
nuxwin committed Oct 24, 2017
1 parent a2f7664 commit 5787464
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 81 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Changelog

All notable changes to this project will be documented in this file, in reverse chronological order by release.

## 1.0.0

### Changed

- Assume 'yes' in non-interactive mode.

### Fixed

- Deprecation Notice: The Composer\Package\LinkConstraint\VersionConstraint class is deprecated...
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Plugin Installer for Roundcube
# i-MSCP Plugin Installer for Roundcube

This installer is a drop-in replacement for the roundcube/plugin-installer.

This installer ensures that plugins end up in the correct directory:

Expand Down Expand Up @@ -29,7 +31,7 @@ This installer ensures that plugins end up in the correct directory:
}
]
"require": {
"roundcube/plugin-installer": "*"
"imscp/roundcube-plugin-installer": "^1.0"
},
"minimum-stability": "dev-master"
}
Expand Down
17 changes: 13 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"name": "roundcube/plugin-installer",
"description": "A composer-installer for Roundcube plugins.",
"name": "imscp/roundcube-plugin-installer",
"description": "i-MSCP composer-installer for Roundcube plugins.",
"type": "composer-installer",
"license": "GPL-3.0+",
"version": "1.0.0",
"authors": [
{
"name": "Thomas Bruederli",
Expand All @@ -11,6 +12,10 @@
{
"name": "Till Klampaeckel",
"email": "[email protected]"
},
{
"name": "Laurent Declercq",
"email": "[email protected]"
}
],
"autoload": {
Expand All @@ -25,9 +30,13 @@
"src/bin/rcubeinitdb.sh"
],
"require": {
"php": ">=5.3.0"
"php": ">=5.3.0",
"composer-plugin-api": "^1.0"
},
"require-dev": {
"composer/composer": "*"
"composer/composer": "^1.0.0-alpha11"
},
"replace": {
"roundcube/plugin-installer": "0.1.*"
}
}
166 changes: 91 additions & 75 deletions src/Roundcube/Composer/PluginInstaller.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
namespace Roundcube\Composer;

use Composer\Installer\LibraryInstaller;
use Composer\Package\Version\VersionParser;
use Composer\Package\LinkConstraint\VersionConstraint;
use Composer\Package\PackageInterface;
use Composer\Package\Version\VersionParser;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Semver\Constraint\Constraint as VersionConstraint;
use Composer\Util\ProcessExecutor;

/**
* @category Plugins
* @package PluginInstaller
* @author Till Klampaeckel <[email protected]>
* @author Thomas Bruederli <[email protected]>
* @author Laurent Declercq <[email protected]>
* @license GPL-3.0+
* @version GIT: <git_id>
* @link http://github.com/roundcube/plugin-installer
Expand All @@ -28,7 +29,8 @@ class PluginInstaller extends LibraryInstaller
public function getInstallPath(PackageInterface $package)
{
static $vendorDir;
if ($vendorDir === null) {

if ($vendorDir === NULL) {
$vendorDir = $this->getVendorDir();
}

Expand All @@ -44,31 +46,34 @@ public function install(InstalledRepositoryInterface $repo, PackageInterface $pa
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;
$configFile = $this->rcubeConfigFile();
$pluginName = $this->getPluginName($package);
$pluginDir = $this->getVendorDir() . DIRECTORY_SEPARATOR . $pluginName;
$extra = $package->getExtra();
$plugin_name = $this->getPluginName($package);
$pluginName = $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 (is_writeable($configFile) && php_sapi_name() == 'cli') {
$answer = $this->io->askConfirmation("Do you want to activate the $pluginName plugin for the i-MSCP Roundcube Webmail Suite? [n|Y] ", true);
if (true === $answer) {
$this->rcubeAlterConfig($plugin_name, true);
$this->rcubeAlterConfig($pluginName, 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)) {
if (is_file($pluginDir . DIRECTORY_SEPARATOR . 'config.inc.php.dist')
&& !is_file($pluginDir . DIRECTORY_SEPARATOR . 'config.inc.php')
&& is_writeable($pluginDir)
) {
$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');
copy($pluginDir . DIRECTORY_SEPARATOR . 'config.inc.php.dist', $pluginDir . 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");
}
if (!empty($extra['roundcube']['sql-dir'])
&& ($sqlDir = realpath($pluginDir . DIRECTORY_SEPARATOR . $extra['roundcube']['sql-dir']))
) {
$this->io->write("<info>Running database initialization script for $pluginName</info>");
system(getcwd() . "/vendor/bin/rcubeinitdb.sh --package=$pluginName --dir=$sqlDir");
}

// run post-install script
Expand All @@ -84,17 +89,16 @@ public function update(InstalledRepositoryInterface $repo, PackageInterface $ini
{
$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;
$pluginName = $this->getPluginName($target);
$pluginDir = $this->getVendorDir() . DIRECTORY_SEPARATOR . $pluginName;

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);
if ($sqlDir = realpath($pluginDir . DIRECTORY_SEPARATOR . $extra['roundcube']['sql-dir'])) {
$this->io->write("<info>Updating database schema for $pluginName</info>");
system(getcwd() . "/bin/updatedb.sh --package=$pluginName --dir=$sqlDir", $res);
}
}

Expand All @@ -112,8 +116,8 @@ public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $
parent::uninstall($repo, $package);

// post-uninstall: deactivate plugin
$plugin_name = $this->getPluginName($package);
$this->rcubeAlterConfig($plugin_name, false);
$pluginName = $this->getPluginName($package);
$this->rcubeAlterConfig($pluginName, false);

// run post-uninstall script
$extra = $package->getExtra();
Expand All @@ -131,44 +135,46 @@ public function supports($packageType)
}

/**
* Setup vendor directory to one of these two:
* ./plugins
* Return vendor directory
*
* @return string
*/
public function getVendorDir()
{
$pluginDir = getcwd();
$pluginDir .= '/plugins';

return $pluginDir;
return getcwd() . '/plugins';
}

/**
* Extract the (valid) plugin name from the package object
*
* @param PackageInterface $package
* @return string
*/
private function getPluginName(PackageInterface $package)
{
@list($vendor, $pluginName) = explode('/', $package->getPrettyName());

@list(, $pluginName) = explode('/', $package->getPrettyName());
return strtr($pluginName, '-', '_');
}

/**
* Check version requirements from the "extra" block of a package
* against the local Roundcube version
*
* @param PackageInterface $package
* @throws \Exception
*/
private function rcubeVersionCheck($package)
private function rcubeVersionCheck(PackageInterface $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)) {
$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");
throw new \Exception("Unable to find a Roundcube installation in $rootDir");
}

$extra = $package->getExtra();
Expand All @@ -179,7 +185,10 @@ private function rcubeVersionCheck($package)
$version = $parser->normalize(str_replace('-git', '.999', $extra['roundcube'][$key]));
$constraint = new VersionConstraint($operator, $version);
if (!$constraint->versionCompare($rcubeVersion, $version, $operator)) {
throw new \Exception("Version check failed! " . $package->getName() . " requires Roundcube version $operator $version, $rcubeVersion was detected.");
throw new \Exception(
"Version check failed! " . $package->getName()
. " requires Roundcube version $operator $version, $rcubeVersion was detected."
);
}
}
}
Expand All @@ -188,61 +197,66 @@ private function rcubeVersionCheck($package)

/**
* Add or remove the given plugin to the list of active plugins in the Roundcube config.
*
* @param string $pluginName
* @param bool $add
* @return bool|int
*/
private function rcubeAlterConfig($plugin_name, $add)
private function rcubeAlterConfig($pluginName, $add)
{
$config_file = $this->rcubeConfigFile();
@include($config_file);
$configFile = $this->rcubeConfigFile();
@include($configFile);
$success = false;
$varname = '$config';

if (empty($config) && !empty($rcmail_config)) {
$config = $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 (is_array($config) && is_writeable($configFile)) {
$configTemplate = @file_get_contents($configFile) ?: '';
$configPlugins = !empty($config['plugins']) ? ((array)$config['plugins']) : array();
$activePlugins = $configPlugins;

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 ($add && !in_array($pluginName, $activePlugins)) {
$activePlugins[] = $pluginName;
} elseif (!$add && ($i = array_search($pluginName, $activePlugins)) !== false) {
unset($activePlugins[$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);
if ($activePlugins != $configPlugins) {
$count = 0;
$varExport = "array(\n\t'" . join("',\n\t'", $activePlugins) . "',\n);";
$newConfig = preg_replace(
"/(\\$varname\['plugins'\])\s+=\s+(.+);/Uims", "\\1 = " . $varExport, $configTemplate, -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);
$varTxt = "\n{$varname}['plugins'] = $varExport;\n";
$newConfig = str_replace('?>', $varTxt . '?>', $configTemplate, $count);

if (!$count) {
$new_config = $config_templ . $var_txt;
$newConfig = $configTemplate . $varTxt;
}
}

$success = file_put_contents($config_file, $new_config);
$success = file_put_contents($configFile, $newConfig);
}
}

if ($success && php_sapi_name() == 'cli') {
$this->io->write("<info>Updated local config at $config_file</info>");
$this->io->write("<info>Updated local config at $configFile</info>");
}

return $success;
}

/**
* Helper method to get an absolute path to the local Roundcube config file
*
* @return bool|string
*/
private function rcubeConfigFile()
{
Expand All @@ -251,29 +265,31 @@ private function rcubeConfigFile()

/**
* Run the given script file
*
* @param $script
* @param PackageInterface $package
*/
private function rcubeRunScript($script, PackageInterface $package)
{
$plugin_name = $this->getPluginName($package);
$plugin_dir = $this->getVendorDir() . DIRECTORY_SEPARATOR . $plugin_name;
$pluginName = $this->getPluginName($package);
$pluginDir = $this->getVendorDir() . DIRECTORY_SEPARATOR . $pluginName;

// check for executable shell script
if (($scriptfile = realpath($plugin_dir . DIRECTORY_SEPARATOR . $script)) && is_executable($scriptfile)) {
$script = $scriptfile;
if (($scriptFile = realpath($pluginDir . DIRECTORY_SEPARATOR . $script)) && is_executable($scriptFile)) {
$script = $scriptFile;
}

// run PHP script in Roundcube context
if ($scriptfile && preg_match('/\.php$/', $scriptfile)) {
if ($scriptFile && preg_match('/\.php$/', $scriptFile)) {
// run PHP script in Roundcube context
$incdir = realpath(getcwd() . '/program/include');
include_once($incdir . '/iniset.php');
include($scriptfile);
}
// attempt to execute the given string as shell commands
else {
include($scriptFile);
} else {
// attempt to execute the given string as shell commands
$process = new ProcessExecutor($this->io);
$exitCode = $process->execute($script, null, $plugin_dir);
$exitCode = $process->execute($script, $output, $pluginDir);
if ($exitCode !== 0) {
throw new \RuntimeException('Error executing script: '. $process->getErrorOutput(), $exitCode);
throw new \RuntimeException('Error executing script: ' . $process->getErrorOutput(), $exitCode);
}
}
}
Expand Down

0 comments on commit 5787464

Please sign in to comment.