diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php
index 02bdd6b71..ce8a588c6 100644
--- a/src/Composer/EventDispatcher/EventDispatcher.php
+++ b/src/Composer/EventDispatcher/EventDispatcher.php
@@ -157,142 +157,148 @@ class EventDispatcher
$this->pushEvent($event);
- $returnMax = 0;
- foreach ($listeners as $callable) {
- $return = 0;
- $this->ensureBinDirIsInPath();
+ try {
+ $returnMax = 0;
+ foreach ($listeners as $callable) {
+ $return = 0;
+ $this->ensureBinDirIsInPath();
- if (!is_string($callable)) {
- if (!is_callable($callable)) {
- $className = is_object($callable[0]) ? get_class($callable[0]) : $callable[0];
+ if (!is_string($callable)) {
+ if (!is_callable($callable)) {
+ $className = is_object($callable[0]) ? get_class($callable[0]) : $callable[0];
- throw new \RuntimeException('Subscriber '.$className.'::'.$callable[1].' for event '.$event->getName().' is not callable, make sure the function is defined and public');
- }
- if (is_array($callable) && (is_string($callable[0]) || is_object($callable[0])) && is_string($callable[1])) {
- $this->io->writeError(sprintf('> %s: %s', $event->getName(), (is_object($callable[0]) ? get_class($callable[0]) : $callable[0]).'->'.$callable[1]), true, IOInterface::VERBOSE);
- }
- $return = false === call_user_func($callable, $event) ? 1 : 0;
- } elseif ($this->isComposerScript($callable)) {
- $this->io->writeError(sprintf('> %s: %s', $event->getName(), $callable), true, IOInterface::VERBOSE);
-
- $script = explode(' ', substr($callable, 1));
- $scriptName = $script[0];
- unset($script[0]);
-
- $args = array_merge($script, $event->getArguments());
- $flags = $event->getFlags();
- if (strpos($callable, '@composer ') === 0) {
- $exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . ' ' . implode(' ', $args);
- if (0 !== ($exitCode = $this->executeTty($exec))) {
- $this->io->writeError(sprintf('Script %s handling the %s event returned with error code '.$exitCode.'', $callable, $event->getName()), true, IOInterface::QUIET);
+ throw new \RuntimeException('Subscriber '.$className.'::'.$callable[1].' for event '.$event->getName().' is not callable, make sure the function is defined and public');
+ }
+ if (is_array($callable) && (is_string($callable[0]) || is_object($callable[0])) && is_string($callable[1])) {
+ $this->io->writeError(sprintf('> %s: %s', $event->getName(), (is_object($callable[0]) ? get_class($callable[0]) : $callable[0]).'->'.$callable[1]), true, IOInterface::VERBOSE);
+ }
+ $return = false === call_user_func($callable, $event) ? 1 : 0;
+ } elseif ($this->isComposerScript($callable)) {
+ $this->io->writeError(sprintf('> %s: %s', $event->getName(), $callable), true, IOInterface::VERBOSE);
+
+ $script = explode(' ', substr($callable, 1));
+ $scriptName = $script[0];
+ unset($script[0]);
+
+ $args = array_merge($script, $event->getArguments());
+ $flags = $event->getFlags();
+ if (strpos($callable, '@composer ') === 0) {
+ $exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . ' ' . implode(' ', $args);
+ if (0 !== ($exitCode = $this->executeTty($exec))) {
+ $this->io->writeError(sprintf('Script %s handling the %s event returned with error code '.$exitCode.'', $callable, $event->getName()), true, IOInterface::QUIET);
+
+ throw new ScriptExecutionException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
+ }
+ } else {
+ if (!$this->getListeners(new Event($scriptName))) {
+ $this->io->writeError(sprintf('You made a reference to a non-existent script %s', $callable), true, IOInterface::QUIET);
+ }
- throw new ScriptExecutionException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
+ try {
+ /** @var InstallerEvent $event */
+ $scriptEvent = new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags);
+ $scriptEvent->setOriginatingEvent($event);
+ $return = $this->dispatch($scriptName, $scriptEvent);
+ } catch (ScriptExecutionException $e) {
+ $this->io->writeError(sprintf('Script %s was called via %s', $callable, $event->getName()), true, IOInterface::QUIET);
+ throw $e;
+ }
}
- } else {
- if (!$this->getListeners(new Event($scriptName))) {
- $this->io->writeError(sprintf('You made a reference to a non-existent script %s', $callable), true, IOInterface::QUIET);
+ } elseif ($this->isPhpScript($callable)) {
+ $className = substr($callable, 0, strpos($callable, '::'));
+ $methodName = substr($callable, strpos($callable, '::') + 2);
+
+ if (!class_exists($className)) {
+ $this->io->writeError('Class '.$className.' is not autoloadable, can not call '.$event->getName().' script', true, IOInterface::QUIET);
+ continue;
+ }
+ if (!is_callable($callable)) {
+ $this->io->writeError('Method '.$callable.' is not callable, can not call '.$event->getName().' script', true, IOInterface::QUIET);
+ continue;
}
try {
- /** @var InstallerEvent $event */
- $scriptEvent = new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags);
- $scriptEvent->setOriginatingEvent($event);
- $return = $this->dispatch($scriptName, $scriptEvent);
- } catch (ScriptExecutionException $e) {
- $this->io->writeError(sprintf('Script %s was called via %s', $callable, $event->getName()), true, IOInterface::QUIET);
+ $return = false === $this->executeEventPhpScript($className, $methodName, $event) ? 1 : 0;
+ } catch (\Exception $e) {
+ $message = "Script %s handling the %s event terminated with an exception";
+ $this->io->writeError(''.sprintf($message, $callable, $event->getName()).'', true, IOInterface::QUIET);
throw $e;
}
- }
- } elseif ($this->isPhpScript($callable)) {
- $className = substr($callable, 0, strpos($callable, '::'));
- $methodName = substr($callable, strpos($callable, '::') + 2);
-
- if (!class_exists($className)) {
- $this->io->writeError('Class '.$className.' is not autoloadable, can not call '.$event->getName().' script', true, IOInterface::QUIET);
- continue;
- }
- if (!is_callable($callable)) {
- $this->io->writeError('Method '.$callable.' is not callable, can not call '.$event->getName().' script', true, IOInterface::QUIET);
- continue;
- }
-
- try {
- $return = false === $this->executeEventPhpScript($className, $methodName, $event) ? 1 : 0;
- } catch (\Exception $e) {
- $message = "Script %s handling the %s event terminated with an exception";
- $this->io->writeError(''.sprintf($message, $callable, $event->getName()).'', true, IOInterface::QUIET);
- throw $e;
- }
- } else {
- $args = implode(' ', array_map(array('Composer\Util\ProcessExecutor', 'escape'), $event->getArguments()));
- $exec = $callable . ($args === '' ? '' : ' '.$args);
- if ($this->io->isVerbose()) {
- $this->io->writeError(sprintf('> %s: %s', $event->getName(), $exec));
- } elseif ($event->getName() !== '__exec_command') {
- // do not output the command being run when using `composer exec` as it is fairly obvious the user is running it
- $this->io->writeError(sprintf('> %s', $exec));
- }
+ } else {
+ $args = implode(' ', array_map(array('Composer\Util\ProcessExecutor', 'escape'), $event->getArguments()));
+ $exec = $callable . ($args === '' ? '' : ' '.$args);
+ if ($this->io->isVerbose()) {
+ $this->io->writeError(sprintf('> %s: %s', $event->getName(), $exec));
+ } elseif ($event->getName() !== '__exec_command') {
+ // do not output the command being run when using `composer exec` as it is fairly obvious the user is running it
+ $this->io->writeError(sprintf('> %s', $exec));
+ }
- $possibleLocalBinaries = $this->composer->getPackage()->getBinaries();
- if ($possibleLocalBinaries) {
- foreach ($possibleLocalBinaries as $localExec) {
- if (preg_match('{\b'.preg_quote($callable).'$}', $localExec)) {
- $caller = BinaryInstaller::determineBinaryCaller($localExec);
- $exec = preg_replace('{^'.preg_quote($callable).'}', $caller . ' ' . $localExec, $exec);
- break;
+ $possibleLocalBinaries = $this->composer->getPackage()->getBinaries();
+ if ($possibleLocalBinaries) {
+ foreach ($possibleLocalBinaries as $localExec) {
+ if (preg_match('{\b'.preg_quote($callable).'$}', $localExec)) {
+ $caller = BinaryInstaller::determineBinaryCaller($localExec);
+ $exec = preg_replace('{^'.preg_quote($callable).'}', $caller . ' ' . $localExec, $exec);
+ break;
+ }
}
}
- }
- if (strpos($exec, '@putenv ') === 0) {
- putenv(substr($exec, 8));
- list($var, $value) = explode('=', substr($exec, 8), 2);
- $_SERVER[$var] = $value;
+ if (strpos($exec, '@putenv ') === 0) {
+ putenv(substr($exec, 8));
+ list($var, $value) = explode('=', substr($exec, 8), 2);
+ $_SERVER[$var] = $value;
- continue;
- }
- if (strpos($exec, '@php ') === 0) {
- $pathAndArgs = substr($exec, 5);
- if (Platform::isWindows()) {
- $pathAndArgs = preg_replace_callback('{^\S+}', function ($path) {
- return str_replace('/', '\\', $path[0]);
- }, $pathAndArgs);
+ continue;
}
- $exec = $this->getPhpExecCommand() . ' ' . $pathAndArgs;
- } else {
- $finder = new PhpExecutableFinder();
- $phpPath = $finder->find(false);
- if ($phpPath) {
- $_SERVER['PHP_BINARY'] = $phpPath;
- putenv('PHP_BINARY=' . $_SERVER['PHP_BINARY']);
+ if (strpos($exec, '@php ') === 0) {
+ $pathAndArgs = substr($exec, 5);
+ if (Platform::isWindows()) {
+ $pathAndArgs = preg_replace_callback('{^\S+}', function ($path) {
+ return str_replace('/', '\\', $path[0]);
+ }, $pathAndArgs);
+ }
+ $exec = $this->getPhpExecCommand() . ' ' . $pathAndArgs;
+ } else {
+ $finder = new PhpExecutableFinder();
+ $phpPath = $finder->find(false);
+ if ($phpPath) {
+ $_SERVER['PHP_BINARY'] = $phpPath;
+ putenv('PHP_BINARY=' . $_SERVER['PHP_BINARY']);
+ }
+
+ if (Platform::isWindows()) {
+ $exec = preg_replace_callback('{^\S+}', function ($path) {
+ return str_replace('/', '\\', $path[0]);
+ }, $exec);
+ }
}
- if (Platform::isWindows()) {
- $exec = preg_replace_callback('{^\S+}', function ($path) {
- return str_replace('/', '\\', $path[0]);
- }, $exec);
+ // if composer is being executed, make sure it runs the expected composer from current path
+ // resolution, even if bin-dir contains composer too because the project requires composer/composer
+ // see https://github.com/composer/composer/issues/8748
+ if (strpos($exec, 'composer ') === 0) {
+ $exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . substr($exec, 8);
}
- }
- // if composer is being executed, make sure it runs the expected composer from current path
- // resolution, even if bin-dir contains composer too because the project requires composer/composer
- // see https://github.com/composer/composer/issues/8748
- if (strpos($exec, 'composer ') === 0) {
- $exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . substr($exec, 8);
+ if (0 !== ($exitCode = $this->executeTty($exec))) {
+ $this->io->writeError(sprintf('Script %s handling the %s event returned with error code '.$exitCode.'', $callable, $event->getName()), true, IOInterface::QUIET);
+
+ throw new ScriptExecutionException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
+ }
}
- if (0 !== ($exitCode = $this->executeTty($exec))) {
- $this->io->writeError(sprintf('Script %s handling the %s event returned with error code '.$exitCode.'', $callable, $event->getName()), true, IOInterface::QUIET);
+ $returnMax = max($returnMax, $return);
- throw new ScriptExecutionException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
+ if ($event->isPropagationStopped()) {
+ break;
}
}
+ } catch (\Exception $e) {
+ $this->popEvent();
- $returnMax = max($returnMax, $return);
-
- if ($event->isPropagationStopped()) {
- break;
- }
+ throw $e;
}
$this->popEvent();