Browse Source

Append the bin dir on each listener iteration

The "composer install" can create the vendor/dir folders and be used as a script item on composer.json. Having another script running after it that relies on vendor/bir binaries (such as phpunit) will cause it to not find the binary. This fix addresses the issue by trying to append the path on each script iteration.
Adriano Ferreira 5 years ago
parent
commit
acc040f745

+ 21 - 15
src/Composer/EventDispatcher/EventDispatcher.php

@@ -145,27 +145,15 @@ class EventDispatcher
      */
     protected function doDispatch(Event $event)
     {
-        $pathStr = 'PATH';
-        if (!isset($_SERVER[$pathStr]) && isset($_SERVER['Path'])) {
-            $pathStr = 'Path';
-        }
-
-        // add the bin dir to the PATH to make local binaries of deps usable in scripts
-        $binDir = $this->composer->getConfig()->get('bin-dir');
-        if (is_dir($binDir)) {
-            $binDir = realpath($binDir);
-            if (isset($_SERVER[$pathStr]) && !preg_match('{(^|'.PATH_SEPARATOR.')'.preg_quote($binDir).'($|'.PATH_SEPARATOR.')}', $_SERVER[$pathStr])) {
-                $_SERVER[$pathStr] = $binDir.PATH_SEPARATOR.getenv($pathStr);
-                putenv($pathStr.'='.$_SERVER[$pathStr]);
-            }
-        }
-
         $listeners = $this->getListeners($event);
 
         $this->pushEvent($event);
 
         $return = 0;
         foreach ($listeners as $callable) {
+
+            $this->ensureBinDirIsInPath();
+
             if (!is_string($callable)) {
                 if (!is_callable($callable)) {
                     $className = is_object($callable[0]) ? get_class($callable[0]) : $callable[0];
@@ -545,4 +533,22 @@ class EventDispatcher
     {
         return array_pop($this->eventStack);
     }
+
+    private function ensureBinDirIsInPath()
+    {
+        $pathStr = 'PATH';
+        if (!isset($_SERVER[$pathStr]) && isset($_SERVER['Path'])) {
+            $pathStr = 'Path';
+        }
+
+        // add the bin dir to the PATH to make local binaries of deps usable in scripts
+        $binDir = $this->composer->getConfig()->get('bin-dir');
+        if (is_dir($binDir)) {
+            $binDir = realpath($binDir);
+            if (isset($_SERVER[$pathStr]) && !preg_match('{(^|'.PATH_SEPARATOR.')'.preg_quote($binDir).'($|'.PATH_SEPARATOR.')}', $_SERVER[$pathStr])) {
+                $_SERVER[$pathStr] = $binDir.PATH_SEPARATOR.getenv($pathStr);
+                putenv($pathStr.'='.$_SERVER[$pathStr]);
+            }
+        }
+    }
 }

+ 54 - 0
tests/Composer/Test/EventDispatcher/EventDispatcherTest.php

@@ -260,6 +260,60 @@ class EventDispatcherTest extends TestCase
         $this->assertEquals($expected, $io->getOutput());
     }
 
+    public function testDispatcherAppendsDirBinOnPathForEveryListener()
+    {
+        $currentDirectoryBkp = getcwd();
+        $composerBinDirBkp   = getenv('COMPOSER_BIN_DIR');
+        chdir(__DIR__);
+        putenv('COMPOSER_BIN_DIR=' . __DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR));
+
+        $process    = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
+        $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->setConstructorArgs(array(
+                $this->createComposerInstance(),
+                $io = new BufferIO('', OutputInterface::VERBOSITY_VERBOSE),
+                $process,
+            ))->setMethods(array(
+                'getListeners',
+            ))->getMock();
+
+        $listeners = array(
+            'Composer\\Test\\EventDispatcher\\EventDispatcherTest::createsVendorBinFolderChecksEnvDoesNotContainsBin',
+            'Composer\\Test\\EventDispatcher\\EventDispatcherTest::createsVendorBinFolderChecksEnvContainsBin',
+        );
+
+        $dispatcher->expects($this->atLeastOnce())->method('getListeners')->will($this->returnValue($listeners));
+
+        $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
+        rmdir(__DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR));
+        rmdir(__DIR__ . sprintf('%svendor', DIRECTORY_SEPARATOR));
+
+        chdir($currentDirectoryBkp);
+        putenv('COMPOSER_BIN_DIR=' . $composerBinDirBkp);
+    }
+
+    static public function createsVendorBinFolderChecksEnvDoesNotContainsBin()
+    {
+        mkdir(__DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), 0700, true);
+        $val = getenv('PATH');
+
+        if ( ! $val ) {
+            $val = getenv('Path');
+        }
+
+        self::assertFalse(strpos($val, __DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
+    }
+
+    static public function createsVendorBinFolderChecksEnvContainsBin()
+    {
+        $val = getenv('PATH');
+
+        if ( ! $val ) {
+            $val = getenv('Path');
+        }
+
+        self::assertNotFalse(strpos($val, __DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
+    }
+
     static public function getTestEnv() {
         $val = getenv('ABC');
         if ($val !== '123') {