Browse Source

Add support for local binaries in scripts, refs #2516

Jordi Boggiano 10 years ago
parent
commit
d9d8d09fe1

+ 13 - 6
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'));
     }
 }

+ 31 - 18
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('<error>'.sprintf($message, $callable, $event->getName()).'</error>');
@@ -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;
     }
 
     /**