From 331bda235c810787be90219f7625cc8a548aa92e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 16 Dec 2014 11:12:13 +0000 Subject: [PATCH] Fix activation of global plugins, fixes #3557 --- src/Composer/Config.php | 23 +++++++++++++++++++++-- src/Composer/Factory.php | 24 ++++++++++++++---------- tests/Composer/Test/ConfigTest.php | 15 +++++++++++++++ tests/Composer/Test/Mock/FactoryMock.php | 4 ++-- 4 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/Composer/Config.php b/src/Composer/Config.php index 176c228eb..4bb2a06c1 100644 --- a/src/Composer/Config.php +++ b/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 * diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index d42c5e7dd..f2aa27e22 100644 --- a/src/Composer/Factory.php +++ b/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; } diff --git a/tests/Composer/Test/ConfigTest.php b/tests/Composer/Test/ConfigTest.php index 521fb634b..04160b63f 100644 --- a/tests/Composer/Test/ConfigTest.php +++ b/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); diff --git a/tests/Composer/Test/Mock/FactoryMock.php b/tests/Composer/Test/Mock/FactoryMock.php index ccbda8040..52c3fbf2e 100644 --- a/tests/Composer/Test/Mock/FactoryMock.php +++ b/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'),