Browse Source

Fix activation of global plugins, fixes #3557

Jordi Boggiano 10 năm trước cách đây
mục cha
commit
331bda235c

+ 21 - 2
src/Composer/Config.php

@@ -55,6 +55,7 @@ class Config
     );
 
     private $config;
+    private $baseDir;
     private $repositories;
     private $configSource;
     private $authConfigSource;
@@ -63,12 +64,13 @@ class Config
     /**
      * @param boolean $useEnvironment Use COMPOSER_ environment variables to replace config settings
      */
-    public function __construct($useEnvironment = true)
+    public function __construct($useEnvironment = true, $baseDir = null)
     {
         // load defaults
         $this->config = static::$defaultConfig;
         $this->repositories = static::$defaultRepositories;
         $this->useEnvironment = (bool) $useEnvironment;
+        $this->baseDir = $baseDir;
     }
 
     public function setConfigSource(ConfigSourceInterface $source)
@@ -167,7 +169,7 @@ class Config
                 $val = rtrim($this->process($this->getComposerEnv($env) ?: $this->config[$key]), '/\\');
                 $val = preg_replace('#^(\$HOME|~)(/|$)#', rtrim(getenv('HOME') ?: getenv('USERPROFILE'), '/\\') . '/', $val);
 
-                return $val;
+                return $this->realpath($val);
 
             case 'cache-ttl':
                 return (int) $this->config[$key];
@@ -294,6 +296,23 @@ class Config
         }, $value);
     }
 
+    /**
+     * Turns relative paths in absolute paths without realpath()
+     *
+     * Since the dirs might not exist yet we can not call realpath or it will fail.
+     *
+     * @param  string $path
+     * @return string
+     */
+    private function realpath($path)
+    {
+        if (substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':') {
+            return $path;
+        }
+
+        return $this->baseDir . '/' . $path;
+    }
+
     /**
      * Reads the value of a Composer environment variable
      *

+ 14 - 10
src/Composer/Factory.php

@@ -89,8 +89,10 @@ class Factory
      * @param  IOInterface|null $io
      * @return Config
      */
-    public static function createConfig(IOInterface $io = null)
+    public static function createConfig(IOInterface $io = null, $cwd = null)
     {
+        $cwd = $cwd ?: getcwd();
+
         // determine home and cache dirs
         $home     = self::getHomeDir();
         $cacheDir = self::getCacheDir($home);
@@ -107,7 +109,7 @@ class Factory
             }
         }
 
-        $config = new Config();
+        $config = new Config(true, $cwd);
 
         // add dirs to the config
         $config->merge(array('config' => array('home' => $home, 'cache-dir' => $cacheDir)));
@@ -192,8 +194,10 @@ class Factory
      * @throws \UnexpectedValueException
      * @return Composer
      */
-    public function createComposer(IOInterface $io, $localConfig = null, $disablePlugins = false, $fullLoad = true)
+    public function createComposer(IOInterface $io, $localConfig = null, $disablePlugins = false, $cwd = null, $fullLoad = true)
     {
+        $cwd = $cwd ?: getcwd();
+
         // load Composer configuration
         if (null === $localConfig) {
             $localConfig = static::getComposerFile();
@@ -205,7 +209,7 @@ class Factory
 
             if (!$file->exists()) {
                 if ($localConfig === './composer.json' || $localConfig === 'composer.json') {
-                    $message = 'Composer could not find a composer.json file in '.getcwd();
+                    $message = 'Composer could not find a composer.json file in '.$cwd;
                 } else {
                     $message = 'Composer could not find the config file: '.$localConfig;
                 }
@@ -218,7 +222,7 @@ class Factory
         }
 
         // Load config and override with local config/auth config
-        $config = static::createConfig($io);
+        $config = static::createConfig($io, $cwd);
         $config->merge($localConfig);
         if (isset($composerFile)) {
             if ($io && $io->isDebug()) {
@@ -348,18 +352,18 @@ class Factory
      */
     protected function createGlobalComposer(IOInterface $io, Config $config, $disablePlugins)
     {
-        $oldCwd = getcwd();
-        if (realpath($config->get('home')) === realpath($oldCwd)) {
+        if (realpath($config->get('home')) === getcwd()) {
             return;
         }
 
         $composer = null;
         try {
-            chdir($config->get('home'));
-            $composer = self::createComposer($io, null, $disablePlugins, false);
+            $composer = self::createComposer($io, $config->get('home') . '/composer.json', $disablePlugins, $config->get('home'), false);
         } catch (\Exception $e) {
+            if ($io->isDebug()) {
+                $io->write('Failed to initialize global composer: '.$e->getMessage());
+            }
         }
-        @chdir($oldCwd);
 
         return $composer;
     }

+ 15 - 0
tests/Composer/Test/ConfigTest.php

@@ -121,6 +121,21 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($home.'/foo', $config->get('cache-dir'));
     }
 
+    public function testRealpathReplacement()
+    {
+        $config = new Config(false, '/foo/bar');
+        $config->merge(array('config' => array(
+            'bin-dir' => '$HOME/foo',
+            'cache-dir' => '/baz/',
+            'vendor-dir' => 'vendor'
+        )));
+
+        $home = rtrim(getenv('HOME') ?: getenv('USERPROFILE'), '\\/');
+        $this->assertEquals('/foo/bar/vendor', $config->get('vendor-dir'));
+        $this->assertEquals($home.'/foo', $config->get('bin-dir'));
+        $this->assertEquals('/baz', $config->get('cache-dir'));
+    }
+
     public function testOverrideGithubProtocols()
     {
         $config = new Config(false);

+ 2 - 2
tests/Composer/Test/Mock/FactoryMock.php

@@ -22,9 +22,9 @@ use Composer\IO\IOInterface;
 
 class FactoryMock extends Factory
 {
-    public static function createConfig(IOInterface $io = null)
+    public static function createConfig(IOInterface $io = null, $cwd = null)
     {
-        $config = new Config();
+        $config = new Config(true, $cwd);
 
         $config->merge(array(
             'config' => array('home' => sys_get_temp_dir().'/composer-test'),