diff --git a/.dockerignore b/.dockerignore
index 9b914fafec..95d7045edf 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -23,7 +23,7 @@
/datas
/docker-compose.*
/logs
-/nodes_modules
+/node_modules
/plugins
/tmp
/vendor
diff --git a/Dockerfile b/Dockerfile
index 4b2614a357..3feefd2d3b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -90,6 +90,7 @@ RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
telnet \
autoconf \
libtool \
+ python \
pkg-config \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists \
@@ -126,7 +127,7 @@ RUN ( \
&& chmod 600 ~/.ssh/id_rsa \
) || echo "Skip SSH key"
-RUN ./docker/phraseanet/install-plugins
+RUN ./docker/phraseanet/plugins/console install
ENTRYPOINT ["/bootstrap/entrypoint.sh"]
diff --git a/docker/phraseanet/entrypoint.sh b/docker/phraseanet/entrypoint.sh
index 1d1fecb989..037fe0aa02 100755
--- a/docker/phraseanet/entrypoint.sh
+++ b/docker/phraseanet/entrypoint.sh
@@ -26,4 +26,6 @@ if [ ${XDEBUG_ENABLED} == "1" ]; then
docker-php-ext-enable xdebug
fi
+./docker/phraseanet/plugins/console init
+
bash -e docker-php-entrypoint $@
diff --git a/docker/phraseanet/install-plugins b/docker/phraseanet/install-plugins
deleted file mode 100755
index d4a5cb01c8..0000000000
--- a/docker/phraseanet/install-plugins
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env php
- $plugin) {
- $plugin = trim($plugin);
- $repo = $plugin;
- $branch = 'master';
- if (1 === preg_match('#^(.+)\(([^)]+)\)$#', $plugin, $matches)) {
- $repo = $matches[1];
- $branch = $matches[2];
- }
-
- $pluginTmpName = 'plugin' . $key;
- $pluginPath = './plugin' . $key;
- if (is_dir($pluginPath)) {
- echo shell_exec(sprintf('rm -rf %s', $pluginPath));
- }
-
- echo sprintf("Installing %s (branch: %s)\n", $repo, $branch);
- runCommand(sprintf('git clone --single-branch --branch %s %s %s', $branch, $repo, $pluginPath));
-
- runCommand(sprintf('bin/setup plugins:add %s', $pluginPath));
-
- echo shell_exec(sprintf('rm -rf %s', $pluginPath));
-}
diff --git a/docker/phraseanet/plugins/InitCommand.php b/docker/phraseanet/plugins/InitCommand.php
new file mode 100644
index 0000000000..23b7d644b7
--- /dev/null
+++ b/docker/phraseanet/plugins/InitCommand.php
@@ -0,0 +1,29 @@
+setName('init')
+ ->setDescription('Initialize plugins');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ foreach (glob('./plugins/*') as $dir) {
+ if (is_dir($dir)) {
+ $output->writeln(sprintf('Init %s plugin', basename($dir)));
+ SubCommand::run(sprintf('bin/setup plugin:add %s', $dir));
+ }
+ }
+
+ return 0;
+ }
+}
diff --git a/docker/phraseanet/plugins/InstallCommand.php b/docker/phraseanet/plugins/InstallCommand.php
new file mode 100644
index 0000000000..7b8a28c4cd
--- /dev/null
+++ b/docker/phraseanet/plugins/InstallCommand.php
@@ -0,0 +1,64 @@
+setName('install')
+ ->setDescription('Install plugins');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $plugins = trim(getenv('PHRASEANET_PLUGINS'));
+ if (empty($plugins)) {
+ $output->writeln('No plugin to install... SKIP');
+
+ return 0;
+ }
+
+ $pluginsDir = 'plugins';
+ if (!is_dir($pluginsDir)) {
+ mkdir($pluginsDir);
+ }
+
+ foreach (explode(' ', $plugins) as $key => $plugin) {
+ $plugin = trim($plugin);
+ $repo = $plugin;
+ $branch = 'master';
+ if (1 === preg_match('#^(.+)\(([^)]+)\)$#', $plugin, $matches)) {
+ $repo = $matches[1];
+ $branch = $matches[2];
+ }
+
+ $pluginPath = './plugin' . $key;
+ if (is_dir($pluginPath)) {
+ SubCommand::run(sprintf('rm -rf %s', $pluginPath));
+ }
+
+ $output->writeln(sprintf('Installing %s (branch: %s)', $repo, $branch));
+ SubCommand::run(sprintf('git clone --single-branch --branch %s %s %s', $branch, $repo, $pluginPath));
+
+ $manifestSrc = $pluginPath.'/manifest.json';
+ if (!file_exists($manifestSrc)) {
+ throw new \Exception(sprintf('Cannot install plugin %s: no manifest.json file found', $plugin));
+ }
+ $pluginDestName = json_decode(file_get_contents($manifestSrc), true)['name'];
+ rename($pluginPath, $pluginsDir.'/'.$pluginDestName);
+ $pluginPath = $pluginsDir.'/'.$pluginDestName;
+
+ if (file_exists($pluginPath.'/composer.json')) {
+ SubCommand::run(sprintf('cd %s && composer install --no-dev', $pluginPath));
+ }
+ }
+
+ return 0;
+ }
+}
diff --git a/docker/phraseanet/plugins/SubCommand.php b/docker/phraseanet/plugins/SubCommand.php
new file mode 100644
index 0000000000..fd2dbc68a1
--- /dev/null
+++ b/docker/phraseanet/plugins/SubCommand.php
@@ -0,0 +1,26 @@
+add(new InstallCommand());
+$application->add(new InitCommand());
+
+$application->run();
diff --git a/lib/Alchemy/Phrasea/Command/Plugin/AbstractPluginCommand.php b/lib/Alchemy/Phrasea/Command/Plugin/AbstractPluginCommand.php
index 2d9d211612..f535c2cd39 100644
--- a/lib/Alchemy/Phrasea/Command/Plugin/AbstractPluginCommand.php
+++ b/lib/Alchemy/Phrasea/Command/Plugin/AbstractPluginCommand.php
@@ -54,33 +54,43 @@ abstract class AbstractPluginCommand extends Command
protected function doInstallPlugin($source, InputInterface $input, OutputInterface $output)
{
- $temporaryDir = $this->container['temporary-filesystem']->createTemporaryDirectory();
-
- $output->write("Importing $source...");
- $this->container['plugins.importer']->import($source, $temporaryDir);
- $output->writeln(" OK");
$output->write("Validating plugin...");
- $manifest = $this->container['plugins.plugins-validator']->validatePlugin($temporaryDir);
+ $manifest = $this->container['plugins.plugins-validator']->validatePlugin($source);
$output->writeln(" OK found ".$manifest->getName()."");
$targetDir = $this->container['plugin.path'] . DIRECTORY_SEPARATOR . $manifest->getName();
+ if (realpath($targetDir) !== realpath($source)) {
+ $temporaryDir = $this->container['temporary-filesystem']->createTemporaryDirectory();
+ $output->write("Importing $source...");
+ $this->container['plugins.importer']->import($source, $temporaryDir);
+ $output->writeln(" OK");
+ $workingDir = $temporaryDir;
+ } else {
+ $workingDir = $targetDir;
+ }
- $output->write("Setting up composer...");
- $this->container['plugins.composer-installer']->install($temporaryDir);
- $output->writeln(" OK");
+ if (!is_dir($workingDir.'/vendor')) {
+ $output->write("Setting up composer...");
+ $this->container['plugins.composer-installer']->install($workingDir);
+ $output->writeln(" OK");
+ }
$output->write("Installing plugin ".$manifest->getName()."...");
- $this->container['filesystem']->mirror($temporaryDir, $targetDir);
+ if (isset($temporaryDir)) {
+ $this->container['filesystem']->mirror($temporaryDir, $targetDir);
+ }
$output->writeln(" OK");
$output->write("Copying public files ".$manifest->getName()."...");
$this->container['plugins.assets-manager']->update($manifest);
$output->writeln(" OK");
- $output->write("Removing temporary directory...");
- $this->container['filesystem']->remove($temporaryDir);
- $output->writeln(" OK");
+ if (isset($temporaryDir)) {
+ $output->write("Removing temporary directory...");
+ $this->container['filesystem']->remove($temporaryDir);
+ $output->writeln(" OK");
+ }
$output->write("Activating plugin...");
$this->container['conf']->set(['plugins', $manifest->getName(), 'enabled'], true);