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\IO\IOInterface;
use Composer\Composer; use Composer\Composer;
use Composer\DependencyResolver\Operation\OperationInterface; use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\Util\ProcessExecutor;
/** /**
* The Event Dispatcher. * The Event Dispatcher.
@ -34,6 +35,7 @@ class EventDispatcher
protected $composer; protected $composer;
protected $io; protected $io;
protected $loader; protected $loader;
protected $process;
/** /**
* Constructor. * Constructor.
@ -41,10 +43,11 @@ class EventDispatcher
* @param Composer $composer The composer instance * @param Composer $composer The composer instance
* @param IOInterface $io The IOInterface 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->composer = $composer;
$this->io = $io; $this->io = $io;
$this->process = $process ?: new ProcessExecutor();
} }
/** /**
@ -78,24 +81,37 @@ class EventDispatcher
$listeners = $this->getListeners($event); $listeners = $this->getListeners($event);
foreach ($listeners as $callable) { foreach ($listeners as $callable) {
$className = substr($callable, 0, strpos($callable, '::')); if ($this->isPhpScript($callable)) {
$methodName = substr($callable, strpos($callable, '::') + 2); $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>'); if (!class_exists($className)) {
continue; $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>'); if (!is_callable($callable)) {
continue; $this->io->write('<warning>Method '.$callable.' is not callable, can not call '.$event->getName().' script</warning>');
} continue;
}
try {
$className::$methodName($event); try {
} catch (\Exception $e) { $className::$methodName($event);
$message = "Script %s handling the %s event terminated with an exception"; } catch (\Exception $e) {
$this->io->write('<error>'.sprintf($message, $callable, $event->getName()).'</error>'); $message = "Script %s handling the %s event terminated with an exception";
throw $e; $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()]; 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"); $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) private function getDispatcherStubForListenersTest($listeners, $io)
{ {
$dispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher') $dispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')

Loading…
Cancel
Save