1
0
Fork 0

Add Config class and system-wide config management, fixes #513

pull/551/head
Jordi Boggiano 2012-04-09 16:10:25 +02:00
parent 61708a1bb1
commit e638182397
3 changed files with 154 additions and 47 deletions

View File

@ -43,6 +43,16 @@ class Composer
return $this->package; return $this->package;
} }
public function setConfig(Config $config)
{
$this->config = $config;
}
public function getConfig()
{
return $this->config;
}
public function setLocker(Locker $locker) public function setLocker(Locker $locker)
{ {
$this->locker = $locker; $this->locker = $locker;

73
src/Composer/Config.php Normal file
View File

@ -0,0 +1,73 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class Config
{
private $config;
public function __construct()
{
// load defaults
$this->config = array(
'process-timeout' => 300,
'vendor-dir' => 'vendor',
'bin-dir' => '{$vendor-dir}/bin',
);
}
public function merge(array $config)
{
// override defaults with given config
if (!empty($config['config']) && is_array($config['config'])) {
$this->config = array_merge_recursive($this->config, $config['config']);
}
}
public function get($key)
{
switch ($key) {
case 'vendor-dir':
case 'bin-dir':
case 'process-timeout':
// convert foo-bar to COMPOSER_FOO_BAR and check if it exists since it overrides the local config
$env = 'COMPOSER_' . strtoupper(strtr($key, '-', '_'));
return $this->process(getenv($env) ?: $this->config[$key]);
default:
return $this->process($this->config[$key]);
}
}
public function has($key)
{
return array_key_exists($key, $this->config);
}
/**
* Replaces {$refs} inside a config string
*
* @param string a config string that can contain {$refs-to-other-config}
* @return string
*/
private function process($value)
{
$config = $this;
return preg_replace_callback('#\{\$(.+)\}#', function ($match) use ($config) {
return $config->get($match[1]);
}, $value);
}
}

View File

@ -27,66 +27,81 @@ use Composer\Util\RemoteFilesystem;
*/ */
class Factory class Factory
{ {
public static function createConfig()
{
// load main Composer configuration
if (!$home = getenv('COMPOSER_HOME')) {
if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
$home = getenv('APPDATA') . '/Composer/';
} else {
$home = getenv('HOME') . '/.composer/';
}
}
$config = new Config();
$file = new JsonFile($home.'config.json');
if ($file->exists()) {
$config->merge($file->read());
}
return $config;
}
/** /**
* Creates a Composer instance * Creates a Composer instance
* *
* @param IOInterface $io IO instance
* @param mixed $localConfig either a configuration array or a filename to read from, if null it will read from the default filename
* @return Composer * @return Composer
*/ */
public function createComposer(IOInterface $io, $composerFile = null) public function createComposer(IOInterface $io, $localConfig = null)
{ {
// load Composer configuration // load Composer configuration
if (null === $composerFile) { if (null === $localConfig) {
$composerFile = getenv('COMPOSER') ?: 'composer.json'; $localConfig = getenv('COMPOSER') ?: 'composer.json';
} }
$file = new JsonFile($composerFile, new RemoteFilesystem($io)); if (is_string($localConfig)) {
$composerFile = $localConfig;
$file = new JsonFile($localConfig, new RemoteFilesystem($io));
if (!$file->exists()) { if (!$file->exists()) {
if ($composerFile === 'composer.json') { if ($localConfig === 'composer.json') {
$message = 'Composer could not find a composer.json file in '.getcwd(); $message = 'Composer could not find a composer.json file in '.getcwd();
} else { } else {
$message = 'Composer could not find the config file: '.$composerFile; $message = 'Composer could not find the config file: '.$localConfig;
} }
$instructions = 'To initialize a project, please create a composer.json file as described in the http://getcomposer.org/ "Getting Started" section'; $instructions = 'To initialize a project, please create a composer.json file as described in the http://getcomposer.org/ "Getting Started" section';
throw new \InvalidArgumentException($message.PHP_EOL.$instructions); throw new \InvalidArgumentException($message.PHP_EOL.$instructions);
} }
// Configuration defaults
$composerConfig = array(
'vendor-dir' => 'vendor',
'process-timeout' => 300,
);
$packageConfig = $file->read();
$file->validateSchema(JsonFile::LAX_SCHEMA); $file->validateSchema(JsonFile::LAX_SCHEMA);
$localConfig = $file->read();
if (isset($packageConfig['config']) && is_array($packageConfig['config'])) {
$packageConfig['config'] = array_merge($composerConfig, $packageConfig['config']);
} else {
$packageConfig['config'] = $composerConfig;
} }
$vendorDir = getenv('COMPOSER_VENDOR_DIR') ?: $packageConfig['config']['vendor-dir']; // Configuration defaults
if (!isset($packageConfig['config']['bin-dir'])) { $config = $this->createConfig();
$packageConfig['config']['bin-dir'] = $vendorDir.'/bin'; $config->merge($localConfig);
}
$binDir = getenv('COMPOSER_BIN_DIR') ?: $packageConfig['config']['bin-dir']; $vendorDir = $config->get('vendor-dir');
$binDir = $config->get('bin-dir');
// setup process timeout // setup process timeout
$processTimeout = getenv('COMPOSER_PROCESS_TIMEOUT') ?: $packageConfig['config']['process-timeout']; ProcessExecutor::setTimeout((int) $config->get('process-timeout'));
ProcessExecutor::setTimeout((int) $processTimeout);
// initialize repository manager // initialize repository manager
$rm = $this->createRepositoryManager($io); $rm = $this->createRepositoryManager($io);
// load default repository unless it's explicitly disabled // load default repository unless it's explicitly disabled
$packageConfig = $this->addPackagistRepository($packageConfig); $localConfig = $this->addPackagistRepository($localConfig);
// load local repository // load local repository
$this->addLocalRepository($rm, $vendorDir); $this->addLocalRepository($rm, $vendorDir);
// load package // load package
$loader = new Package\Loader\RootPackageLoader($rm); $loader = new Package\Loader\RootPackageLoader($rm);
$package = $loader->load($packageConfig); $package = $loader->load($localConfig);
// initialize download manager // initialize download manager
$dm = $this->createDownloadManager($io); $dm = $this->createDownloadManager($io);
@ -97,18 +112,21 @@ class Factory
// purge packages if they have been deleted on the filesystem // purge packages if they have been deleted on the filesystem
$this->purgePackages($rm, $im); $this->purgePackages($rm, $im);
// init locker
$lockFile = substr($composerFile, -5) === '.json' ? substr($composerFile, 0, -4).'lock' : $composerFile . '.lock';
$locker = new Package\Locker(new JsonFile($lockFile, new RemoteFilesystem($io)), $rm, md5_file($composerFile));
// initialize composer // initialize composer
$composer = new Composer(); $composer = new Composer();
$composer->setConfig($config);
$composer->setPackage($package); $composer->setPackage($package);
$composer->setLocker($locker);
$composer->setRepositoryManager($rm); $composer->setRepositoryManager($rm);
$composer->setDownloadManager($dm); $composer->setDownloadManager($dm);
$composer->setInstallationManager($im); $composer->setInstallationManager($im);
// init locker if possible
if (isset($composerFile)) {
$lockFile = substr($composerFile, -5) === '.json' ? substr($composerFile, 0, -4).'lock' : $composerFile . '.lock';
$locker = new Package\Locker(new JsonFile($lockFile, new RemoteFilesystem($io)), $rm, md5_file($composerFile));
$composer->setLocker($locker);
}
return $composer; return $composer;
} }
@ -131,18 +149,19 @@ class Factory
$rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json'))); $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json')));
} }
protected function addPackagistRepository(array $packageConfig) protected function addPackagistRepository(array $localConfig)
{ {
$loadPackagist = true; $loadPackagist = true;
$packagistConfig = array( $packagistConfig = array(
'type' => 'composer', 'type' => 'composer',
'url' => 'http://packagist.org' 'url' => 'http://packagist.org'
); );
if (isset($packageConfig['repositories'])) {
foreach ($packageConfig['repositories'] as $key => $repo) { if (isset($localConfig['repositories'])) {
foreach ($localConfig['repositories'] as $key => $repo) {
if (isset($repo['packagist'])) { if (isset($repo['packagist'])) {
if (true === $repo['packagist']) { if (true === $repo['packagist']) {
$packageConfig['repositories'][$key] = $packagistConfig; $localConfig['repositories'][$key] = $packagistConfig;
} }
$loadPackagist = false; $loadPackagist = false;
@ -150,14 +169,14 @@ class Factory
} }
} }
} else { } else {
$packageConfig['repositories'] = array(); $localConfig['repositories'] = array();
} }
if ($loadPackagist) { if ($loadPackagist) {
$packageConfig['repositories'][] = $packagistConfig; $localConfig['repositories'][] = $packagistConfig;
} }
return $packageConfig; return $localConfig;
} }
public function createDownloadManager(IOInterface $io) public function createDownloadManager(IOInterface $io)
@ -194,10 +213,15 @@ class Factory
} }
} }
static public function create(IOInterface $io, $composerFile = null) /**
* @param IOInterface $io IO instance
* @param mixed $config either a configuration array or a filename to read from, if null it will read from the default filename
* @return Composer
*/
static public function create(IOInterface $io, $config = null)
{ {
$factory = new static(); $factory = new static();
return $factory->createComposer($io, $composerFile); return $factory->createComposer($io, $config);
} }
} }