From d9d8d09fe10497d0d688a1cbd24815fe55239529 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 20 Jul 2014 19:46:51 +0200 Subject: [PATCH] Add support for local binaries in scripts, refs #2516 --- src/Composer/Command/RunScriptCommand.php | 19 ++++--- .../EventDispatcher/EventDispatcher.php | 49 ++++++++++++------- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/Composer/Command/RunScriptCommand.php b/src/Composer/Command/RunScriptCommand.php index 527d8693d..50449b89d 100644 --- a/src/Composer/Command/RunScriptCommand.php +++ b/src/Composer/Command/RunScriptCommand.php @@ -12,6 +12,7 @@ namespace Composer\Command; +use Composer\Script\CommandEvent; use Composer\Script\ScriptEvents; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -75,16 +76,22 @@ EOT } } - $hasListeners = $this->getComposer()->getEventDispatcher()->hasEventListeners(new \Composer\Script\CommandEvent($script, $this->getComposer(), $this->getIO())); + $composer = $this->getComposer(); + $hasListeners = $composer->getEventDispatcher()->hasEventListeners(new CommandEvent($script, $composer, $this->getIO())); + if (!$hasListeners) { + throw new \InvalidArgumentException(sprintf('Script "%s" is not defined in this package', $script)); + } - if(!$hasListeners) { - throw new \InvalidArgumentException(sprintf('Script "%s" does not exist', $script)); + // add the bin dir to the PATH to make local binaries of deps usable in scripts + $binDir = $composer->getConfig()->get('bin-dir'); + if (is_dir($binDir)) { + putenv('PATH='.realpath($binDir).PATH_SEPARATOR.getenv('PATH')); } if (in_array($script, $this->commandEvents)) { - $this->getComposer()->getEventDispatcher()->dispatchCommandEvent($script, $input->getOption('dev') || !$input->getOption('no-dev')); - } else { - $this->getComposer()->getEventDispatcher()->dispatchScript($script, $input->getOption('dev') || !$input->getOption('no-dev')); + return $composer->getEventDispatcher()->dispatchCommandEvent($script, $input->getOption('dev') || !$input->getOption('no-dev')); } + + return $composer->getEventDispatcher()->dispatchScript($script, $input->getOption('dev') || !$input->getOption('no-dev')); } } diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index 3b116961b..c1d3be064 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -57,8 +57,10 @@ class EventDispatcher /** * Dispatch an event * - * @param string $eventName An event name - * @param Event $event + * @param string $eventName An event name + * @param Event $event + * @return int return code of the executed script if any, for php scripts a false return + * value is changed to 1, anything else to 0 */ public function dispatch($eventName, Event $event = null) { @@ -66,47 +68,55 @@ class EventDispatcher $event = new Event($eventName); } - $this->doDispatch($event); + return $this->doDispatch($event); } /** * Dispatch a script event. * - * @param string $eventName The constant in ScriptEvents - * @param Script\Event $event + * @param string $eventName The constant in ScriptEvents + * @param Script\Event $event + * @return int return code of the executed script if any, for php scripts a false return + * value is changed to 1, anything else to 0 */ public function dispatchScript($eventName, $devMode = false) { - $this->doDispatch(new Script\Event($eventName, $this->composer, $this->io, $devMode)); + return $this->doDispatch(new Script\Event($eventName, $this->composer, $this->io, $devMode)); } /** * Dispatch a package event. * - * @param string $eventName The constant in ScriptEvents - * @param boolean $devMode Whether or not we are in dev mode - * @param OperationInterface $operation The package being installed/updated/removed + * @param string $eventName The constant in ScriptEvents + * @param boolean $devMode Whether or not we are in dev mode + * @param OperationInterface $operation The package being installed/updated/removed + * @return int return code of the executed script if any, for php scripts a false return + * value is changed to 1, anything else to 0 */ public function dispatchPackageEvent($eventName, $devMode, OperationInterface $operation) { - $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $operation)); + return $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $operation)); } /** * Dispatch a command event. * - * @param string $eventName The constant in ScriptEvents - * @param boolean $devMode Whether or not we are in dev mode + * @param string $eventName The constant in ScriptEvents + * @param boolean $devMode Whether or not we are in dev mode + * @return int return code of the executed script if any, for php scripts a false return + * value is changed to 1, anything else to 0 */ public function dispatchCommandEvent($eventName, $devMode) { - $this->doDispatch(new CommandEvent($eventName, $this->composer, $this->io, $devMode)); + return $this->doDispatch(new CommandEvent($eventName, $this->composer, $this->io, $devMode)); } /** * Triggers the listeners of an event. * * @param Event $event The event object to pass to the event handlers/listeners. + * @return int return code of the executed script if any, for php scripts a false return + * value is changed to 1, anything else to 0 * @throws \RuntimeException * @throws \Exception */ @@ -114,9 +124,10 @@ class EventDispatcher { $listeners = $this->getListeners($event); + $return = 0; foreach ($listeners as $callable) { if (!is_string($callable) && is_callable($callable)) { - call_user_func($callable, $event); + $return = false === call_user_func($callable, $event) ? 1 : 0; } elseif ($this->isPhpScript($callable)) { $className = substr($callable, 0, strpos($callable, '::')); $methodName = substr($callable, strpos($callable, '::') + 2); @@ -131,7 +142,7 @@ class EventDispatcher } try { - $this->executeEventPhpScript($className, $methodName, $event); + $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->write(''.sprintf($message, $callable, $event->getName()).''); @@ -149,6 +160,8 @@ class EventDispatcher break; } } + + return $return; } /** @@ -158,7 +171,7 @@ class EventDispatcher */ protected function executeEventPhpScript($className, $methodName, Event $event) { - $className::$methodName($event); + return $className::$methodName($event); } /** @@ -219,14 +232,14 @@ class EventDispatcher /** * Checks if an event has listeners registered * - * @param Event $event + * @param Event $event * @return boolean */ public function hasEventListeners(Event $event) { $listeners = $this->getListeners($event); - return (sizeof($listeners) > 0); + return count($listeners) > 0; } /**