Merge branch '1.1'
commit
b8974a3e13
|
@ -183,6 +183,84 @@ class AwsPlugin implements PluginInterface, EventSubscriberInterface
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Plugin capabilities
|
||||||
|
|
||||||
|
Composer defines a standard set of capabilities which may be implemented by plugins.
|
||||||
|
Their goal is to make the plugin ecosystem more stable as it reduces the need to mess
|
||||||
|
with [`Composer\Composer`][4]'s internal state, by providing explicit extension points
|
||||||
|
for common plugin requirements.
|
||||||
|
|
||||||
|
Capable Plugins classes must implement the [`Composer\Plugin\Capable`][8] interface
|
||||||
|
and declare their capabilities in the `getCapabilities()` method.
|
||||||
|
This method must return an array, with the _key_ as a Composer Capability class name,
|
||||||
|
and the _value_ as the Plugin's own implementation class name of said Capability:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace My\Composer;
|
||||||
|
|
||||||
|
use Composer\Composer;
|
||||||
|
use Composer\IO\IOInterface;
|
||||||
|
use Composer\Plugin\PluginInterface;
|
||||||
|
use Composer\Plugin\Capable;
|
||||||
|
|
||||||
|
class Plugin implements PluginInterface, Capable
|
||||||
|
{
|
||||||
|
public function activate(Composer $composer, IOInterface $io)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCapabilities()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'Composer\Plugin\Capability\CommandProvider' => 'My\Composer\CommandProvider',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command provider
|
||||||
|
|
||||||
|
The [`Composer\Plugin\Capability\CommandProvider`][9] capability allows to register
|
||||||
|
additional commands for Composer :
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace My\Composer;
|
||||||
|
|
||||||
|
use Composer\Plugin\Capability\CommandProvider as CommandProviderCapability;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Composer\Command\BaseCommand;
|
||||||
|
|
||||||
|
class CommandProvider implements CommandProviderCapability
|
||||||
|
{
|
||||||
|
public function getCommands()
|
||||||
|
{
|
||||||
|
return array(new Command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Command extends BaseCommand
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('custom-plugin-command');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$output->writeln('Executing');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now the `custom-plugin-command` is available alongside Composer commands.
|
||||||
|
|
||||||
|
> _Composer commands are based on the [Symfony Console Component][10]._
|
||||||
|
|
||||||
## Using Plugins
|
## Using Plugins
|
||||||
|
|
||||||
Plugin packages are automatically loaded as soon as they are installed and will
|
Plugin packages are automatically loaded as soon as they are installed and will
|
||||||
|
@ -202,3 +280,6 @@ local project plugins are loaded.
|
||||||
[5]: https://github.com/composer/composer/blob/master/src/Composer/IO/IOInterface.php
|
[5]: https://github.com/composer/composer/blob/master/src/Composer/IO/IOInterface.php
|
||||||
[6]: https://github.com/composer/composer/blob/master/src/Composer/EventDispatcher/EventSubscriberInterface.php
|
[6]: https://github.com/composer/composer/blob/master/src/Composer/EventDispatcher/EventSubscriberInterface.php
|
||||||
[7]: ../01-basic-usage.md#package-versions
|
[7]: ../01-basic-usage.md#package-versions
|
||||||
|
[8]: https://github.com/composer/composer/blob/master/src/Composer/Plugin/Capable.php
|
||||||
|
[9]: https://github.com/composer/composer/blob/master/src/Composer/Plugin/Capability/CommandProvider.php
|
||||||
|
[10]: http://symfony.com/doc/current/components/console/introduction.html
|
||||||
|
|
|
@ -79,6 +79,18 @@ abstract class BaseCommand extends Command
|
||||||
$this->getApplication()->resetComposer();
|
$this->getApplication()->resetComposer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this command is meant to call another command.
|
||||||
|
*
|
||||||
|
* This is mainly needed to avoid duplicated warnings messages.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isProxyCommand()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return IOInterface
|
* @return IOInterface
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -80,4 +80,12 @@ EOT
|
||||||
|
|
||||||
return $this->getApplication()->run($input, $output);
|
return $this->getApplication()->run($input, $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function isProxyCommand()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,4 +71,12 @@ EOT
|
||||||
|
|
||||||
return $this->getApplication()->run($input, $output);
|
return $this->getApplication()->run($input, $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function isProxyCommand()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,8 @@ class Application extends BaseApplication
|
||||||
/_/
|
/_/
|
||||||
';
|
';
|
||||||
|
|
||||||
|
private $hasPluginCommands = false;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
static $shutdownRegistered = false;
|
static $shutdownRegistered = false;
|
||||||
|
@ -108,7 +110,7 @@ class Application extends BaseApplication
|
||||||
$io = $this->io = new ConsoleIO($input, $output, $this->getHelperSet());
|
$io = $this->io = new ConsoleIO($input, $output, $this->getHelperSet());
|
||||||
ErrorHandler::register($io);
|
ErrorHandler::register($io);
|
||||||
|
|
||||||
// determine command name to be executed
|
// determine command name to be executed without including plugin commands
|
||||||
$commandName = '';
|
$commandName = '';
|
||||||
if ($name = $this->getCommandName($input)) {
|
if ($name = $this->getCommandName($input)) {
|
||||||
try {
|
try {
|
||||||
|
@ -117,7 +119,27 @@ class Application extends BaseApplication
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$isProxyCommand = $commandName === 'global' || $commandName === 'outdated';
|
if (!$input->hasParameterOption('--no-plugins') && !$this->hasPluginCommands && 'global' !== $commandName) {
|
||||||
|
foreach ($this->getPluginCommands() as $command) {
|
||||||
|
if ($this->has($command->getName())) {
|
||||||
|
$io->writeError('<warning>Plugin command '.$command->getName().' ('.get_class($command).') would override a Composer command and has been skipped</warning>');
|
||||||
|
} else {
|
||||||
|
$this->add($command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->hasPluginCommands = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine command name to be executed incl plugin commands, and check if it's a proxy command
|
||||||
|
$isProxyCommand = false;
|
||||||
|
if ($name = $this->getCommandName($input)) {
|
||||||
|
try {
|
||||||
|
$command = $this->find($name);
|
||||||
|
$commandName = $command->getName();
|
||||||
|
$isProxyCommand = ($command instanceof Command\BaseCommand && $command->isProxyCommand());
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$isProxyCommand) {
|
if (!$isProxyCommand) {
|
||||||
$io->writeError(sprintf(
|
$io->writeError(sprintf(
|
||||||
|
@ -197,16 +219,6 @@ class Application extends BaseApplication
|
||||||
$this->io->enableDebugging($startTime);
|
$this->io->enableDebugging($startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$input->hasParameterOption('--no-plugins') && !$isProxyCommand) {
|
|
||||||
foreach ($this->getPluginCommands() as $command) {
|
|
||||||
if ($this->has($command->getName())) {
|
|
||||||
$io->writeError('<warning>Plugin command '.$command->getName().' ('.get_class($command).') would override a Composer command and has been skipped</warning>');
|
|
||||||
} else {
|
|
||||||
$this->add($command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = parent::doRun($input, $output);
|
$result = parent::doRun($input, $output);
|
||||||
|
|
||||||
if (isset($oldWorkingDir)) {
|
if (isset($oldWorkingDir)) {
|
||||||
|
|
|
@ -25,7 +25,12 @@ class ApplicationTest extends TestCase
|
||||||
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
|
||||||
$inputMock->expects($this->once())
|
$inputMock->expects($this->any())
|
||||||
|
->method('hasParameterOption')
|
||||||
|
->with($this->equalTo('--no-plugins'))
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$inputMock->expects($this->any())
|
||||||
->method('getFirstArgument')
|
->method('getFirstArgument')
|
||||||
->will($this->returnValue('list'));
|
->will($this->returnValue('list'));
|
||||||
|
|
||||||
|
@ -68,7 +73,7 @@ class ApplicationTest extends TestCase
|
||||||
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
|
||||||
$inputMock->expects($this->once())
|
$inputMock->expects($this->any())
|
||||||
->method('getFirstArgument')
|
->method('getFirstArgument')
|
||||||
->will($this->returnValue($command));
|
->will($this->returnValue($command));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue