1
0
Fork 0

Merge pull request #551 from Seldaek/config

Add Config class and system-wide config management, fixes #513
pull/568/head
Nils Adermann 2012-04-09 07:39:45 -07:00
commit f93ec9daa4
8 changed files with 208 additions and 77 deletions

View File

@ -25,15 +25,10 @@ class Cache
private $root; private $root;
private $enabled = true; private $enabled = true;
public function __construct(IOInterface $io, $cacheKey = null) public function __construct(IOInterface $io, $cacheDir)
{ {
$this->io = $io; $this->io = $io;
$this->root = rtrim($cacheDir, '/\\') . '/';
if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
$this->root = getenv('APPDATA') . rtrim('/Composer/cache/' . $cacheKey, '/') . '/';
} else {
$this->root = getenv('HOME') . rtrim('/.composer/cache/' . $cacheKey, '/') . '/';
}
if (!is_dir($this->root)) { if (!is_dir($this->root)) {
if (!@mkdir($this->root, 0777, true)) { if (!@mkdir($this->root, 0777, true)) {

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;

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

@ -0,0 +1,93 @@
<?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',
);
}
/**
* Merges new config values with the existing ones (overriding)
*
* @param array $config
*/
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']);
}
}
/**
* Returns a setting
*
* @param string $key
* @return mixed
*/
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]);
case 'home':
return rtrim($this->process($this->config[$key]), '/\\');
default:
return $this->process($this->config[$key]);
}
}
/**
* Checks whether a setting exists
*
* @param string $key
* @return Boolean
*/
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,84 @@ 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());
}
// add home dir to the config
$config->merge(array('config' => array('home' => $home)));
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)) {
if (!$file->exists()) { $composerFile = $localConfig;
if ($composerFile === 'composer.json') { $file = new JsonFile($localConfig, new RemoteFilesystem($io));
$message = 'Composer could not find a composer.json file in '.getcwd();
} else { if (!$file->exists()) {
$message = 'Composer could not find the config file: '.$composerFile; if ($localConfig === 'composer.json') {
$message = 'Composer could not find a composer.json file in '.getcwd();
} else {
$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';
throw new \InvalidArgumentException($message.PHP_EOL.$instructions);
} }
$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); $file->validateSchema(JsonFile::LAX_SCHEMA);
$localConfig = $file->read();
} }
// Configuration defaults // Configuration defaults
$composerConfig = array( $config = $this->createConfig();
'vendor-dir' => 'vendor', $config->merge($localConfig);
'process-timeout' => 300,
);
$packageConfig = $file->read(); $vendorDir = $config->get('vendor-dir');
$file->validateSchema(JsonFile::LAX_SCHEMA); $binDir = $config->get('bin-dir');
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'];
if (!isset($packageConfig['config']['bin-dir'])) {
$packageConfig['config']['bin-dir'] = $vendorDir.'/bin';
}
$binDir = getenv('COMPOSER_BIN_DIR') ?: $packageConfig['config']['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, $config);
// 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,24 +115,27 @@ 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;
} }
protected function createRepositoryManager(IOInterface $io) protected function createRepositoryManager(IOInterface $io, Config $config)
{ {
$rm = new RepositoryManager($io); $rm = new RepositoryManager($io, $config);
$rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository'); $rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository');
$rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository'); $rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository');
$rm->setRepositoryClass('package', 'Composer\Repository\PackageRepository'); $rm->setRepositoryClass('package', 'Composer\Repository\PackageRepository');
@ -131,18 +152,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 +172,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 +216,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);
} }
} }

View File

@ -16,6 +16,7 @@ use Composer\Package\Loader\ArrayLoader;
use Composer\Package\LinkConstraint\VersionConstraint; use Composer\Package\LinkConstraint\VersionConstraint;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Cache; use Composer\Cache;
use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Util\RemoteFilesystem; use Composer\Util\RemoteFilesystem;
@ -29,20 +30,20 @@ class ComposerRepository extends ArrayRepository
protected $packages; protected $packages;
protected $cache; protected $cache;
public function __construct(array $config, IOInterface $io) public function __construct(array $repoConfig, IOInterface $io, Config $config)
{ {
if (!preg_match('{^\w+://}', $config['url'])) { if (!preg_match('{^\w+://}', $repoConfig['url'])) {
// assume http as the default protocol // assume http as the default protocol
$config['url'] = 'http://'.$config['url']; $repoConfig['url'] = 'http://'.$repoConfig['url'];
} }
$config['url'] = rtrim($config['url'], '/'); $repoConfig['url'] = rtrim($repoConfig['url'], '/');
if (function_exists('filter_var') && !filter_var($config['url'], FILTER_VALIDATE_URL)) { if (function_exists('filter_var') && !filter_var($repoConfig['url'], FILTER_VALIDATE_URL)) {
throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$config['url']); throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$repoConfig['url']);
} }
$this->url = $config['url']; $this->url = $repoConfig['url'];
$this->io = $io; $this->io = $io;
$this->cache = new Cache($io, preg_replace('{[^a-z0-9.]}', '-', $this->url)); $this->cache = new Cache($io, $config->get('home').'/cache/'.preg_replace('{[^a-z0-9.]}', '-', $this->url));
} }
protected function initialize() protected function initialize()

View File

@ -16,6 +16,7 @@ use Composer\IO\IOInterface;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\Util\RemoteFilesystem; use Composer\Util\RemoteFilesystem;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Config;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
/** /**
@ -31,18 +32,18 @@ class PearRepository extends ArrayRepository
private $io; private $io;
private $rfs; private $rfs;
public function __construct(array $config, IOInterface $io, RemoteFilesystem $rfs = null) public function __construct(array $repoConfig, IOInterface $io, Config $config, RemoteFilesystem $rfs = null)
{ {
if (!preg_match('{^https?://}', $config['url'])) { if (!preg_match('{^https?://}', $repoConfig['url'])) {
$config['url'] = 'http://'.$config['url']; $repoConfig['url'] = 'http://'.$repoConfig['url'];
} }
if (function_exists('filter_var') && !filter_var($config['url'], FILTER_VALIDATE_URL)) { if (function_exists('filter_var') && !filter_var($repoConfig['url'], FILTER_VALIDATE_URL)) {
throw new \UnexpectedValueException('Invalid url given for PEAR repository: '.$config['url']); throw new \UnexpectedValueException('Invalid url given for PEAR repository: '.$repoConfig['url']);
} }
$this->url = rtrim($config['url'], '/'); $this->url = rtrim($repoConfig['url'], '/');
$this->channel = !empty($config['channel']) ? $config['channel'] : null; $this->channel = !empty($repoConfig['channel']) ? $repoConfig['channel'] : null;
$this->io = $io; $this->io = $io;
$this->rfs = $rfs ?: new RemoteFilesystem($this->io); $this->rfs = $rfs ?: new RemoteFilesystem($this->io);
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Repository; namespace Composer\Repository;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Config;
/** /**
* Repositories manager. * Repositories manager.
@ -27,10 +28,12 @@ class RepositoryManager
private $repositories = array(); private $repositories = array();
private $repositoryClasses = array(); private $repositoryClasses = array();
private $io; private $io;
private $config;
public function __construct(IOInterface $io) public function __construct(IOInterface $io, Config $config)
{ {
$this->io = $io; $this->io = $io;
$this->config = $config;
} }
/** /**
@ -94,7 +97,7 @@ class RepositoryManager
} }
$class = $this->repositoryClasses[$type]; $class = $this->repositoryClasses[$type];
return new $class($config, $this->io); return new $class($config, $this->io, $this->config);
} }
/** /**

View File

@ -19,6 +19,7 @@ use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Config;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
@ -32,7 +33,7 @@ class VcsRepository extends ArrayRepository
protected $versionParser; protected $versionParser;
protected $type; protected $type;
public function __construct(array $config, IOInterface $io, array $drivers = null) public function __construct(array $repoConfig, IOInterface $io, Config $config = null, array $drivers = null)
{ {
$this->drivers = $drivers ?: array( $this->drivers = $drivers ?: array(
'github' => 'Composer\Repository\Vcs\GitHubDriver', 'github' => 'Composer\Repository\Vcs\GitHubDriver',
@ -43,9 +44,9 @@ class VcsRepository extends ArrayRepository
'hg' => 'Composer\Repository\Vcs\HgDriver', 'hg' => 'Composer\Repository\Vcs\HgDriver',
); );
$this->url = $config['url']; $this->url = $repoConfig['url'];
$this->io = $io; $this->io = $io;
$this->type = isset($config['type']) ? $config['type'] : 'vcs'; $this->type = isset($repoConfig['type']) ? $repoConfig['type'] : 'vcs';
$this->verbose = $io->isVerbose(); $this->verbose = $io->isVerbose();
} }