diff --git a/src/Composer/Script/EventDispatcher.php b/src/Composer/Script/EventDispatcher.php
index b4537ed62..6c6d26b87 100644
--- a/src/Composer/Script/EventDispatcher.php
+++ b/src/Composer/Script/EventDispatcher.php
@@ -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 ($this->isPhpScript($callable)) {
+ $className = substr($callable, 0, strpos($callable, '::'));
+ $methodName = substr($callable, strpos($callable, '::') + 2);
- if (!class_exists($className)) {
- $this->io->write('Class '.$className.' is not autoloadable, can not call '.$event->getName().' script');
- continue;
- }
- if (!is_callable($callable)) {
- $this->io->write('Method '.$callable.' is not callable, can not call '.$event->getName().' script');
- continue;
- }
+ if (!class_exists($className)) {
+ $this->io->write('Class '.$className.' is not autoloadable, can not call '.$event->getName().' script');
+ continue;
+ }
+ if (!is_callable($callable)) {
+ $this->io->write('Method '.$callable.' is not callable, can not call '.$event->getName().' script');
+ continue;
+ }
- try {
- $className::$methodName($event);
- } catch (\Exception $e) {
- $message = "Script %s handling the %s event terminated with an exception";
- $this->io->write(''.sprintf($message, $callable, $event->getName()).'');
- throw $e;
+ try {
+ $className::$methodName($event);
+ } catch (\Exception $e) {
+ $message = "Script %s handling the %s event terminated with an exception";
+ $this->io->write(''.sprintf($message, $callable, $event->getName()).'');
+ 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(''.$message.'', $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, '::');
+ }
}
diff --git a/tests/Composer/Test/Script/EventDispatcherTest.php b/tests/Composer/Test/Script/EventDispatcherTest.php
index e23dccf8a..682624d9f 100644
--- a/tests/Composer/Test/Script/EventDispatcherTest.php
+++ b/tests/Composer/Test/Script/EventDispatcherTest.php
@@ -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')