Add ability to call CLI-based commands from an event

main
John Kary 12 years ago
parent 62bb5b339b
commit be90496952

@ -16,6 +16,7 @@ use Composer\Autoload\AutoloadGenerator;
use Composer\IO\IOInterface;
use Composer\Composer;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\Util\ProcessExecutor;
/**
* The Event Dispatcher.
@ -34,6 +35,7 @@ class EventDispatcher
protected $composer;
protected $io;
protected $loader;
protected $process;
/**
* Constructor.
@ -41,10 +43,11 @@ class EventDispatcher
* @param Composer $composer The composer instance
* @param IOInterface $io The IOInterface instance
*/
public function __construct(Composer $composer, IOInterface $io)
public function __construct(Composer $composer, IOInterface $io, ProcessExecutor $process = null)
{
$this->composer = $composer;
$this->io = $io;
$this->process = $process ?: new ProcessExecutor();
}
/**
@ -78,24 +81,37 @@ class EventDispatcher
$listeners = $this->getListeners($event);
foreach ($listeners as $callable) {
$className = substr($callable, 0, strpos($callable, '::'));
$methodName = substr($callable, strpos($callable, '::') + 2);
if (!class_exists($className)) {
$this->io->write('<warning>Class '.$className.' is not autoloadable, can not call '.$event->getName().' script</warning>');
continue;
}
if (!is_callable($callable)) {
$this->io->write('<warning>Method '.$callable.' is not callable, can not call '.$event->getName().' script</warning>');
continue;
}
try {
$className::$methodName($event);
} catch (\Exception $e) {
$message = "Script %s handling the %s event terminated with an exception";
$this->io->write('<error>'.sprintf($message, $callable, $event->getName()).'</error>');
throw $e;
if ($this->isPhpScript($callable)) {
$className = substr($callable, 0, strpos($callable, '::'));
$methodName = substr($callable, strpos($callable, '::') + 2);
if (!class_exists($className)) {
$this->io->write('<warning>Class '.$className.' is not autoloadable, can not call '.$event->getName().' script</warning>');
continue;
}
if (!is_callable($callable)) {
$this->io->write('<warning>Method '.$callable.' is not callable, can not call '.$event->getName().' script</warning>');
continue;
}
try {
$className::$methodName($event);
} catch (\Exception $e) {
$message = "Script %s handling the %s event terminated with an exception";
$this->io->write('<error>'.sprintf($message, $callable, $event->getName()).'</error>');
throw $e;
}
} else {
$callback = function ($type, $buffer) use ($event, $callable) {
$io = $event->getIO();
if ('err' === $type) {
$message = 'Script %s handling the %s event returned an error: %s';
$io->write(sprintf('<error>'.$message.'</error>', $callable, $event->getName(), $buffer));
} else {
$io->write($buffer, false);
}
};
$this->process->execute($callable, $callback);
}
}
}
@ -126,4 +142,15 @@ class EventDispatcher
return $scripts[$event->getName()];
}
/**
* Checks if string given references a class path and method
*
* @param string $callable
* @return boolean
*/
protected function isPhpScript($callable)
{
return false !== strpos($callable, '::');
}
}

@ -35,6 +35,32 @@ class EventDispatcherTest extends TestCase
$dispatcher->dispatchCommandEvent("post-install-cmd");
}
public function testDispatcherCanExecuteCommandLineScripts()
{
$eventCliCommand = 'phpunit';
$process = $this->getMock('Composer\Util\ProcessExecutor');
$dispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')
->setConstructorArgs(array(
$this->getMock('Composer\Composer'),
$this->getMock('Composer\IO\IOInterface'),
$process,
))
->setMethods(array('getListeners'))
->getMock();
$listeners = array($eventCliCommand);
$dispatcher->expects($this->atLeastOnce())
->method('getListeners')
->will($this->returnValue($listeners));
$process->expects($this->once())
->method('execute')
->with($eventCliCommand);
$dispatcher->dispatchCommandEvent("post-install-cmd");
}
private function getDispatcherStubForListenersTest($listeners, $io)
{
$dispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')

Loading…
Cancel
Save