Add enable/disable plugins commands

This commit is contained in:
Romain Neutron
2014-02-21 16:10:56 +01:00
parent 53cb47d0b7
commit fb693836d5
14 changed files with 224 additions and 113 deletions

View File

@@ -18,6 +18,8 @@ use Alchemy\Phrasea\Command\Setup\PluginsReset;
use Alchemy\Phrasea\Command\Plugin\ListPlugin; use Alchemy\Phrasea\Command\Plugin\ListPlugin;
use Alchemy\Phrasea\Command\Plugin\AddPlugin; use Alchemy\Phrasea\Command\Plugin\AddPlugin;
use Alchemy\Phrasea\Command\Plugin\RemovePlugin; use Alchemy\Phrasea\Command\Plugin\RemovePlugin;
use Alchemy\Phrasea\Command\Plugin\EnablePlugin;
use Alchemy\Phrasea\Command\Plugin\DisablePlugin;
use Alchemy\Phrasea\CLI; use Alchemy\Phrasea\CLI;
use Alchemy\Phrasea\Command\Setup\CheckEnvironment; use Alchemy\Phrasea\Command\Setup\CheckEnvironment;
use Alchemy\Phrasea\Core\CLIProvider\DoctrineMigrationServiceProvider; use Alchemy\Phrasea\Core\CLIProvider\DoctrineMigrationServiceProvider;
@@ -65,6 +67,8 @@ $app->command(new AddPlugin());
$app->command(new ListPlugin()); $app->command(new ListPlugin());
$app->command(new RemovePlugin()); $app->command(new RemovePlugin());
$app->command(new PluginsReset()); $app->command(new PluginsReset());
$app->command(new EnablePlugin());
$app->command(new DisablePlugin());
$app->command(new CheckEnvironment('check:system')); $app->command(new CheckEnvironment('check:system'));
$app->command(new Install('system:install')); $app->command(new Install('system:install'));

View File

@@ -1,7 +1,50 @@
<?php <?php
/**
* Created by PhpStorm. /*
* User: romain * This file is part of Phraseanet
* Date: 21/02/2014 *
* Time: 16:00 * (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/ */
namespace Alchemy\Phrasea\Command\Plugin;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class DisablePlugin extends AbstractPluginCommand
{
public function __construct()
{
parent::__construct('plugins:disable');
$this->setDescription('Disables a plugin')
->addArgument('name', InputArgument::REQUIRED, 'The name of the plugin');
}
protected function doExecutePluginAction(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
if (!$this->container['plugins.manager']->hasPlugin($name)) {
$output->writeln(sprintf('There is no plugin named <comment>%s</comment>, aborting', $name));
return 0;
}
if (!$this->container['plugins.manager']->isEnabled($name)) {
$output->writeln(sprintf('Plugin named <comment>%s</comment> is already disabled, aborting', $name));
return 0;
}
$this->container['plugins.manager']->disable($name);
$output->writeln(sprintf('Plugin named <info>%s</info> is now disabled', $name));
return 0;
}
}

View File

@@ -12,6 +12,7 @@
namespace Alchemy\Phrasea\Plugin\Management; namespace Alchemy\Phrasea\Plugin\Management;
use Alchemy\Phrasea\Plugin\Exception\RegistrationFailureException; use Alchemy\Phrasea\Plugin\Exception\RegistrationFailureException;
use Alchemy\Phrasea\Plugin\Schema\Manifest;
class AutoloaderGenerator class AutoloaderGenerator
{ {
@@ -90,7 +91,7 @@ EOF;
<?php <?php
// This file is automatically generated, please do not edit it. // This file is automatically generated, please do not edit it.
// To update configuration, use bin/console plugins:* commands. // To update configuration, use bin/setup plugins:* commands.
return call_user_func(function () { return call_user_func(function () {
EOF; EOF;
@@ -122,7 +123,7 @@ EOF;
<?php <?php
// This file is automatically generated, please do not edit it. // This file is automatically generated, please do not edit it.
// To update configuration, use bin/console plugins:* commands. // To update configuration, use bin/setup plugins:* commands.
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
@@ -131,12 +132,14 @@ return call_user_func(function (Application \$app) {
EOF; EOF;
foreach ($manifests as $manifest) { foreach ($manifests as $manifest) {
$pluginBuffer = '';
foreach ($manifest->getServices() as $service) { foreach ($manifest->getServices() as $service) {
$class = $service['class']; $class = $service['class'];
$buffer .= <<<EOF $pluginBuffer .= <<<EOF
\$app->register($class::create(\$app)); \$app->register($class::create(\$app));
EOF; EOF;
} }
$buffer .= $this->wrapWithConditionnal($manifest, $pluginBuffer);
} }
$buffer .= <<<EOF $buffer .= <<<EOF
@@ -149,27 +152,44 @@ EOF;
return $buffer; return $buffer;
} }
private function wrapWithConditionnal(Manifest $manifest, $wrapped)
{
if (trim($wrapped) === '') {
return '';
}
$name = $manifest->getName();
return <<<EOF
if (\$app['plugins.manager']->isEnabled('$name')) {
$wrapped
}
EOF;
}
private function createCommands($manifests) private function createCommands($manifests)
{ {
$buffer = <<<EOF $buffer = <<<EOF
<?php <?php
// This file is automatically generated, please do not edit it. // This file is automatically generated, please do not edit it.
// To update configuration, use bin/console plugins:* commands. // To update configuration, use bin/setup plugins:* commands.
use Alchemy\Phrasea\CLI; use Alchemy\Phrasea\CLI;
return call_user_func(function (CLI \$cli) { return call_user_func(function (CLI \$cli) {
\$app = \$cli;
EOF; EOF;
foreach ($manifests as $manifest) { foreach ($manifests as $manifest) {
$pluginBuffer = '';
foreach ($manifest->getCommands() as $command) { foreach ($manifest->getCommands() as $command) {
$class = $command['class']; $class = $command['class'];
$buffer .= <<<EOF $pluginBuffer .= <<<EOF
\$cli->command($class::create()); \$cli->command($class::create());
EOF; EOF;
} }
$buffer .= $this->wrapWithConditionnal($manifest, $pluginBuffer);
} }
$buffer .= <<<EOF $buffer .= <<<EOF
@@ -188,33 +208,40 @@ EOF;
<?php <?php
// This file is automatically generated, please do not edit it. // This file is automatically generated, please do not edit it.
// To update configuration, use bin/console plugins:* commands. // To update configuration, use bin/setup plugins:* commands.
return array( use Alchemy\Phrasea\Application;
return call_user_func(function (Application \$app) {
\$paths = array();
EOF; EOF;
foreach ($manifests as $manifest) { foreach ($manifests as $manifest) {
$pluginBuffer = '';
$namespace = $this->quote('plugin-' . $manifest->getName()); $namespace = $this->quote('plugin-' . $manifest->getName());
$path = DIRECTORY_SEPARATOR . $manifest->getName() . DIRECTORY_SEPARATOR . 'views'; $path = DIRECTORY_SEPARATOR . $manifest->getName() . DIRECTORY_SEPARATOR . 'views';
if (is_dir($this->pluginDirectory . $path)) { if (is_dir($this->pluginDirectory . $path)) {
$path = $this->quote($path); $path = $this->quote($path);
$buffer .= <<<EOF $pluginBuffer .= <<<EOF
$namespace => __DIR__ . $path, \$paths[$namespace] = __DIR__ . $path;
EOF; EOF;
} }
foreach ($manifest->getTwigPaths() as $path) { foreach ($manifest->getTwigPaths() as $path) {
$path = $this->quote(DIRECTORY_SEPARATOR . $manifest->getName() . DIRECTORY_SEPARATOR . $path); $path = $this->quote(DIRECTORY_SEPARATOR . $manifest->getName() . DIRECTORY_SEPARATOR . $path);
$buffer .= <<<EOF $pluginBuffer .= <<<EOF
__DIR__ . $path, \$paths[] = __DIR__ . $path;
EOF; EOF;
} }
$buffer .= $this->wrapWithConditionnal($manifest, $pluginBuffer);
} }
$buffer .= <<<EOF $buffer .= <<<EOF
);
return \$paths;
}, \$app);
EOF; EOF;
@@ -223,6 +250,6 @@ EOF;
private function quote($string) private function quote($string)
{ {
return "'".str_replace("'", "\'", $string)."'"; return "'".str_replace("'", "\\'", $string)."'";
} }
} }

View File

@@ -3,4 +3,10 @@
// This file is automatically generated, please do not edit it. // This file is automatically generated, please do not edit it.
// To update configuration, use bin/setup plugins:* commands. // To update configuration, use bin/setup plugins:* commands.
return []; use Alchemy\Phrasea\Application;
return call_user_func(function (Application $app) {
$paths = array();
return $paths;
}, $app);

View File

@@ -1,7 +1,7 @@
<?php <?php
// This file is automatically generated, please do not edit it. // This file is automatically generated, please do not edit it.
// To update configuration, use bin/console plugins:* commands. // To update configuration, use bin/setup plugins:* commands.
return call_user_func(function () { return call_user_func(function () {
$loader = require __DIR__ . '/../vendor/autoload.php'; $loader = require __DIR__ . '/../vendor/autoload.php';

View File

@@ -1,11 +1,11 @@
<?php <?php
// This file is automatically generated, please do not edit it. // This file is automatically generated, please do not edit it.
// To update configuration, use bin/console plugins:* commands. // To update configuration, use bin/setup plugins:* commands.
use Alchemy\Phrasea\CLI; use Alchemy\Phrasea\CLI;
return call_user_func(function (CLI $cli) { return call_user_func(function (CLI $cli) {
$app = $cli;
return $cli; return $cli;
}, $cli); }, $cli);

View File

@@ -1,7 +1,7 @@
<?php <?php
// This file is automatically generated, please do not edit it. // This file is automatically generated, please do not edit it.
// To update configuration, use bin/console plugins:* commands. // To update configuration, use bin/setup plugins:* commands.
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;

View File

@@ -1,7 +1,12 @@
<?php <?php
// This file is automatically generated, please do not edit it. // This file is automatically generated, please do not edit it.
// To update configuration, use bin/console plugins:* commands. // To update configuration, use bin/setup plugins:* commands.
return array( use Alchemy\Phrasea\Application;
);
return call_user_func(function (Application $app) {
$paths = array();
return $paths;
}, $app);

View File

@@ -0,0 +1,35 @@
<?php
namespace Alchemy\Tests\Phrasea\Command\Plugin;
use Alchemy\Phrasea\Command\Plugin\DisablePlugin;
use Symfony\Component\Yaml\Yaml;
class DisablePluginTest extends PluginCommandTestCase
{
/**
* @dataProvider provideVariousInitialConfs
*/
public function testExecute($initial)
{
$input = $this->getMock('Symfony\Component\Console\Input\InputInterface');
$output = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
$input->expects($this->once())
->method('getArgument')
->with($this->equalTo('name'))
->will($this->returnValue('test-plugin'));
self::$DI['cli']['conf']->set(['plugins', 'test-plugin', 'enabled'], $initial);
$command = new DisablePlugin();
$command->setContainer(self::$DI['cli']);
$this->assertSame(0, $command->execute($input, $output));
$this->assertFalse(self::$DI['cli']['conf']->get(['plugins', 'test-plugin', 'enabled']));
}
public function provideVariousInitialConfs()
{
return [[true], [false]];
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Alchemy\Tests\Phrasea\Command\Plugin;
use Alchemy\Phrasea\Command\Plugin\EnablePlugin;
use Alchemy\Phrasea\Core\Provider\ConfigurationServiceProvider;
use Symfony\Component\Yaml\Yaml;
class EnablePluginTest extends PluginCommandTestCase
{
/**
* @dataProvider provideVariousInitialConfs
*/
public function testExecute($initial)
{
$input = $this->getMock('Symfony\Component\Console\Input\InputInterface');
$output = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
$input->expects($this->once())
->method('getArgument')
->with($this->equalTo('name'))
->will($this->returnValue('test-plugin'));
self::$DI['cli']['conf']->set(['plugins', 'test-plugin', 'enabled'], $initial);
$command = new EnablePlugin();
$command->setContainer(self::$DI['cli']);
$this->assertSame(0, $command->execute($input, $output));
$this->assertTrue(self::$DI['cli']['conf']->get(['plugins', 'test-plugin', 'enabled']));
}
public function provideVariousInitialConfs()
{
return [[true], [false]];
}
}

View File

@@ -15,13 +15,6 @@ class RemovePluginTest extends PluginCommandTestCase
->method('getArgument') ->method('getArgument')
->with($this->equalTo('name')) ->with($this->equalTo('name'))
->will($this->returnValue($name)); ->will($this->returnValue($name));
$input->expects($this->any())
->method('getOption')
->will($this->returnCallback(function ($option) {
if ($option === 'keep-config') {
return false;
}
}));
$output = $this->getMock('Symfony\Component\Console\Output\OutputInterface'); $output = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
@@ -54,56 +47,6 @@ class RemovePluginTest extends PluginCommandTestCase
$this->assertArrayNotHasKey('test-plugin', $conf['plugins']); $this->assertArrayNotHasKey('test-plugin', $conf['plugins']);
} }
public function testExecuteWithoutRemoveConfig()
{
$name = 'test-plugin';
$input = $this->getMock('Symfony\Component\Console\Input\InputInterface');
$input->expects($this->once())
->method('getArgument')
->with($this->equalTo('name'))
->will($this->returnValue($name));
$input->expects($this->any())
->method('getOption')
->will($this->returnCallback(function ($option) {
if ($option === 'keep-config') {
return true;
}
}));
$output = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
$command = new RemovePlugin();
$command->setContainer(self::$DI['cli']);
self::$DI['cli']['plugins.manager'] = $this->getMockBuilder('Alchemy\Phrasea\Plugin\PluginManager')
->disableOriginalConstructor()
->getMock();
self::$DI['cli']['plugins.manager']->expects($this->once())
->method('hasPlugin')
->with('test-plugin')
->will($this->returnValue(true));
$data = $this->addPluginData();
self::$DI['cli']['filesystem'] = $this->createFilesystemMock();
self::$DI['cli']['filesystem']->expects($this->at(0))
->method('remove')
->with(self::$DI['cli']['root.path'].'/www/plugins/'.$name);
self::$DI['cli']['filesystem']->expects($this->at(1))
->method('remove')
->with(self::$DI['cli']['plugins.directory'].'/'.$name);
$result = $command->execute($input, $output);
$this->assertSame(0, $result);
$conf = self::$DI['cli']['phraseanet.configuration']->getConfig();
$this->assertSame($data, $conf['plugins']['test-plugin']);
}
private function addPluginData() private function addPluginData()
{ {
$data = ['key' => 'value']; $data = ['key' => 'value'];

View File

@@ -13,26 +13,6 @@ class PluginServiceProviderTest extends ServiceProviderTestCase
public function provideServiceDescription() public function provideServiceDescription()
{ {
return [ return [
[
'Alchemy\Phrasea\Core\CLIProvider\PluginServiceProvider',
'plugins.json-validator',
'JsonSchema\Validator'
],
[
'Alchemy\Phrasea\Core\CLIProvider\PluginServiceProvider',
'plugins.manager',
'Alchemy\Phrasea\Plugin\PluginManager'
],
[
'Alchemy\Phrasea\Core\CLIProvider\PluginServiceProvider',
'plugins.plugins-validator',
'Alchemy\Phrasea\Plugin\Schema\PluginValidator'
],
[
'Alchemy\Phrasea\Core\CLIProvider\PluginServiceProvider',
'plugins.manifest-validator',
'Alchemy\Phrasea\Plugin\Schema\ManifestValidator'
],
[ [
'Alchemy\Phrasea\Core\CLIProvider\PluginServiceProvider', 'Alchemy\Phrasea\Core\CLIProvider\PluginServiceProvider',
'plugins.import-strategy', 'plugins.import-strategy',
@@ -111,11 +91,4 @@ class PluginServiceProviderTest extends ServiceProviderTestCase
$app->register(new PluginServiceProvider()); $app->register(new PluginServiceProvider());
$this->assertInstanceOf('Alchemy\Phrasea\Plugin\Management\ComposerInstaller', $app['plugins.composer-installer']); $this->assertInstanceOf('Alchemy\Phrasea\Plugin\Management\ComposerInstaller', $app['plugins.composer-installer']);
} }
private function createRegistryMock()
{
return $this->getMockBuilder('registry')
->disableOriginalConstructor()
->getMock();
}
} }

View File

@@ -0,0 +1,37 @@
<?php
namespace Alchemy\Tests\Phrasea\Core\Provider;
use Symfony\Component\Process\ExecutableFinder;
/**
* @covers Alchemy\Phrasea\Core\Provider\PluginServiceProvider
*/
class PluginServiceProviderTest extends ServiceProviderTestCase
{
public function provideServiceDescription()
{
return [
[
'Alchemy\Phrasea\Core\Provider\PluginServiceProvider',
'plugins.json-validator',
'JsonSchema\Validator'
],
[
'Alchemy\Phrasea\Core\Provider\PluginServiceProvider',
'plugins.manager',
'Alchemy\Phrasea\Plugin\PluginManager'
],
[
'Alchemy\Phrasea\Core\Provider\PluginServiceProvider',
'plugins.plugins-validator',
'Alchemy\Phrasea\Plugin\Schema\PluginValidator'
],
[
'Alchemy\Phrasea\Core\Provider\PluginServiceProvider',
'plugins.manifest-validator',
'Alchemy\Phrasea\Plugin\Schema\ManifestValidator'
],
];
}
}

View File

@@ -27,8 +27,9 @@ class AutoloaderGeneratorTest extends \PhraseanetTestCase
$this->cleanup($files); $this->cleanup($files);
$manifest = new Manifest(json_decode(file_get_contents($pluginDir . '/manifest.json'), true));
$generator = new AutoloaderGenerator($pluginsDir); $generator = new AutoloaderGenerator($pluginsDir);
$generator->write([new Manifest(json_decode(file_get_contents($pluginDir . '/manifest.json'), true))]); $generator->write([$manifest]);
$finder = new ExecutableFinder(); $finder = new ExecutableFinder();
$php = $finder->find('php'); $php = $finder->find('php');
@@ -52,6 +53,7 @@ class AutoloaderGeneratorTest extends \PhraseanetTestCase
// load services // load services
$app = new Application(); $app = new Application();
$app['conf']->set(['plugins', $manifest->getName(), 'enabled'], true);
$retrievedApp = require $pluginsDir . '/services.php'; $retrievedApp = require $pluginsDir . '/services.php';
$this->assertSame($app, $retrievedApp); $this->assertSame($app, $retrievedApp);