Merge branch '3.8'

Conflicts:
	bin/console
	composer.lock
This commit is contained in:
Nicolas Le Goff
2014-01-31 14:59:53 +01:00
14 changed files with 584 additions and 614 deletions

View File

@@ -11,6 +11,7 @@
namespace KonsoleKommander;
use Alchemy\Phrasea\Command\Plugin\ListPlugin;
use Alchemy\Phrasea\Command\SearchEngine\IndexFull;
use Alchemy\Phrasea\Command\BuildMissingSubdefs;
use Alchemy\Phrasea\Command\CreateCollection;
@@ -103,6 +104,7 @@ $cli->command(new RescanTechnicalDatas('records:rescan-technical-datas'));
$cli->command(new BuildMissingSubdefs('records:build-missing-subdefs'));
$cli->command(new AddPlugin());
$cli->command(new ListPlugin());
$cli->command(new RemovePlugin());
$cli->command(new Configuration());
$cli->command(new XSendFileConfigurationDumper());

View File

@@ -24,7 +24,7 @@
"jms/serializer" : "~0.10",
"justinrainbow/json-schema" : "~1.3",
"mediavorus/mediavorus" : "~0.4.0",
"media-alchemyst/media-alchemyst" : "~0.4, >=0.4.3",
"media-alchemyst/media-alchemyst" : "~0.4, >=0.4.4",
"monolog/monolog" : "~1.3",
"mrclay/minify" : "~2.1.6",
"neutron/process-manager" : "~1.0",

829
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,90 @@
<?php
/*
* This file is part of Phraseanet
*
* (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 Alchemy\Phrasea\Plugin\Plugin;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class ListPlugin extends AbstractPluginCommand
{
public function __construct()
{
parent::__construct('plugins:list');
$this
->setDescription('Lists installed plugins')
->addOption('json', 'j', InputOption::VALUE_NONE, 'Output result in JSON');
}
protected function doExecute(InputInterface $input, OutputInterface $output)
{
$plugins = array_map(function (Plugin $plugin) use ($input) {
if ($plugin->isErroneous()) {
return $this->formatErroneousPlugin($input, $plugin);
}
return $this->formatPlugin($input, $plugin);
}, $this->container['plugins.manager']->listPlugins());
if ($input->getOption('json')) {
$output->writeln(json_encode(array('plugins' => array_values($plugins))));
} else {
$table = $this->getHelperSet()->get('table');
$table
->setHeaders(array('Name', 'Version', 'Description'))
->setRows($plugins)
;
$table->render($output);
}
return 0;
}
private function formatPlugin(InputInterface $input, Plugin $plugin)
{
if ($input->getOption('json')) {
return array(
'name' => $plugin->getName(),
'version' => $plugin->getManifest()->getVersion(),
'description' => $plugin->getManifest()->getDescription(),
'error' => false,
);
}
return array(
$plugin->getName(),
$plugin->getManifest()->getVersion(),
$plugin->getManifest()->getDescription(),
);
}
private function formatErroneousPlugin(InputInterface $input, Plugin $plugin)
{
if ($input->getOption('json')) {
return array(
'name' => $plugin->getName(),
'error' => true,
'description' => 'Error : '.$plugin->getError()->getMessage(),
'version' => null,
);
}
return array(
'<error>' . $plugin->getName() . '</error>',
'<error>Error : ' . $plugin->getError()->getMessage() . '</error>',
'',
);
}
}

View File

@@ -47,11 +47,6 @@ class Step35 implements DatasUpgraderInterface
$this->ensureMigrateColumn($databox);
$sql = 'TRUNCATE metadatas';
$stmt = $databox->get_connection()->prepare($sql);
$stmt->execute();
$stmt->closeCursor();
do {
$rs = $this->getEmptyOriginalNameRecords($databox);

View File

@@ -11,6 +11,7 @@
namespace Alchemy\Phrasea\Core\CLIProvider;
use Alchemy\Phrasea\Plugin\PluginManager;
use Alchemy\Phrasea\Plugin\Schema\ManifestValidator;
use Alchemy\Phrasea\Plugin\Management\PluginsExplorer;
use Alchemy\Phrasea\Plugin\Management\ComposerInstaller;
@@ -31,6 +32,10 @@ class PluginServiceProvider implements ServiceProviderInterface
{
$app['plugins.schema'] = realpath(__DIR__ . '/../../../../conf.d/plugin-schema.json');
$app['plugins.manager'] = $app->share(function (Application $app) {
return new PluginManager($app['plugins.directory'], $app['plugins.plugins-validator']);
});
$app['plugins.json-validator'] = $app->share(function (Application $app) {
return new JsonValidator();
});

View File

@@ -0,0 +1,65 @@
<?php
/*
* This file is part of Phraseanet
*
* (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\Plugin;
use Alchemy\Phrasea\Plugin\Exception\PluginValidationException;
use Alchemy\Phrasea\Plugin\Schema\Manifest;
class Plugin
{
private $error;
private $manifest;
private $name;
public function __construct($name, Manifest $manifest = null, PluginValidationException $error = null)
{
if ($manifest === $error || (null !== $manifest && null !== $error)) {
throw new \LogicException('A plugin is either installed (with a stable manifest) or on error (given its error).');
}
$this->name = $name;
$this->manifest = $manifest;
$this->error = $error;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return Boolean
*/
public function isErroneous()
{
return null !== $this->error;
}
/**
* @return Manifest
*/
public function getManifest()
{
return $this->manifest;
}
/**
* @return PluginValidationException
*/
public function getError()
{
return $this->error;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of Phraseanet
*
* (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\Plugin;
use Alchemy\Phrasea\Plugin\Schema\PluginValidator;
use Alchemy\Phrasea\Plugin\Exception\PluginValidationException;
use Symfony\Component\Finder\Finder;
class PluginManager
{
private $pluginDir;
private $validator;
public function __construct($pluginDir, PluginValidator $validator)
{
$this->pluginDir = $pluginDir;
$this->validator = $validator;
}
/**
* @return Plugin[] An array containing plugins
*/
public function listPlugins()
{
$finder = new Finder();
$finder
->depth(0)
->in($this->pluginDir)
->directories();
$plugins = array();
foreach ($finder as $pluginDir) {
$manifest = $error = null;
$name = $pluginDir->getBasename();
try {
$manifest = $this->validator->validatePlugin((string) $pluginDir);
} catch (PluginValidationException $e) {
$error = $e;
}
$plugins[$name] = new Plugin($name, $manifest, $error);
}
return $plugins;
}
public function hasPlugin($name)
{
$plugins = $this->listPlugins();
return isset($plugins[$name]);
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Alchemy\Tests\Phrasea\Command\Plugin;
use Alchemy\Phrasea\Command\Plugin\ListPlugin;
class ListPluginTest extends PluginCommandTestCase
{
public function testExecute()
{
$input = $this->getMock('Symfony\Component\Console\Input\InputInterface');
$output = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
$table = $this->getMockBuilder('Symfony\Component\Console\Helper\TableHelper')
->disableOriginalConstructor()
->getMock();
$table->expects($this->once())
->method('setHeaders')
->will($this->returnSelf());
$helperSet = $this->getMockBuilder('Symfony\Component\Console\Helper\HelperSet')
->disableOriginalConstructor()
->getMock();
$helperSet->expects($this->once())
->method('get')
->will($this->returnValue($table));
$command = new ListPlugin();
$command->setContainer(self::$DI['cli']);
$command->setHelperSet($helperSet);
$result = $command->execute($input, $output);
$this->assertSame(0, $result);
}
}

View File

@@ -19,6 +19,11 @@ class PluginServiceProviderTest extends ServiceProviderTestCase
'JsonSchema\Validator'
],
[
'Alchemy\Phrasea\Core\CLIProvider\PluginServiceProvider',
'plugins.manager',
'Alchemy\Phrasea\Plugin\PluginManager'
),
array(
'Alchemy\Phrasea\Core\CLIProvider\PluginServiceProvider',
'plugins.plugins-validator',
'Alchemy\Phrasea\Plugin\Schema\PluginValidator'

View File

@@ -0,0 +1,43 @@
<?php
namespace Alchemy\Tests\Phrasea\Plugin;
use Alchemy\Phrasea\Plugin\PluginManager;
use Alchemy\Phrasea\Plugin\Schema\PluginValidator;
class PluginManagerTest extends PluginTestCase
{
public function testListGoodPlugins()
{
$manager = new PluginManager(__DIR__ . '/Fixtures/PluginDirInstalled', self::$DI['cli']['plugins.plugins-validator']);
$plugins = $manager->listPlugins();
$this->assertCount(1, $plugins);
$plugin = array_pop($plugins);
$this->assertFalse($plugin->isErroneous());
}
public function testListWrongPlugins()
{
$manager = new PluginManager(__DIR__ . '/Fixtures/WrongPlugins', self::$DI['cli']['plugins.plugins-validator']);
$plugins = $manager->listPlugins();
$this->assertCount(8, $plugins);
$plugin = array_pop($plugins);
$this->assertTrue($plugin->isErroneous());
}
public function testHasPlugin()
{
$manager = new PluginManager(__DIR__ . '/Fixtures/PluginDirInstalled', self::$DI['cli']['plugins.plugins-validator']);
$this->assertTrue($manager->hasPlugin('test-plugin'));
$this->assertFalse($manager->hasPlugin('test-plugin2'));
}
private function createValidatorMock()
{
return $this->getMockBuilder('Alchemy\Phrasea\Plugin\Schema\PluginValidator')
->disableOriginalConstructor()
->getMock();
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Alchemy\Tests\Phrasea\Plugin;
use Alchemy\Phrasea\Plugin\Plugin;
class PluginTest extends PluginTestCase
{
public function testGetters()
{
$manifest = $this->createManifestMock();
$error = $this->getMock('Alchemy\Phrasea\Plugin\Exception\PluginValidationException');
$plugin = new Plugin('toto', $manifest, null);
$this->assertSame('toto', $plugin->getName());
$this->assertSame($manifest, $plugin->getManifest());
$this->assertNull($plugin->getError());
$this->assertFalse($plugin->isErroneous());
$plugin = new Plugin('toto', null, $error);
$this->assertSame('toto', $plugin->getName());
$this->assertNull($plugin->getManifest());
$this->assertSame($error, $plugin->getError());
$this->assertTrue($plugin->isErroneous());
}
/**
* @expectedException \LogicException
*/
public function testBothNull()
{
new Plugin('toto', null, null);
}
/**
* @expectedException \LogicException
*/
public function testBothNotNull()
{
$manifest = $this->createManifestMock();
$error = $this->getMock('Alchemy\Phrasea\Plugin\Exception\PluginValidationException');
new Plugin('toto', $manifest, $error);
}
}

View File

@@ -30,4 +30,11 @@ class PluginTestCase extends \PhraseanetTestCase
{
return __DIR__ . '/../../../../../lib/conf.d/plugin-schema.json';
}
protected function createManifestMock()
{
return $this->getMockBuilder('Alchemy\Phrasea\Plugin\Schema\Manifest')
->disableOriginalConstructor()
->getMock();
}
}