diff --git a/res/composer-schema.json b/res/composer-schema.json index ac84d5eb0..2e74a97f7 100644 --- a/res/composer-schema.json +++ b/res/composer-schema.json @@ -117,8 +117,8 @@ "description": "If true, the Composer autoloader will also look for classes in the PHP include path." }, "preferred-install": { - "type": "string", - "description": "The install method Composer will prefer to use, defaults to auto and can be any of source, dist or auto." + "type": ["string", "object"], + "description": "The install method Composer will prefer to use, defaults to auto and can be any of source, dist, auto, or a hash of {\"pattern\": \"preference\"}." }, "notify-on-install": { "type": "boolean", diff --git a/src/Composer/Config.php b/src/Composer/Config.php index b6d942c51..ead9c67a8 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -108,6 +108,20 @@ class Config foreach ($config['config'] as $key => $val) { if (in_array($key, array('github-oauth', 'http-basic')) && isset($this->config[$key])) { $this->config[$key] = array_merge($this->config[$key], $val); + } elseif ('preferred-install' === $key && isset($this->config[$key])) { + if (is_string($val)) { + $val = array('*' => $val); + } + if (is_string($this->config[$key])) { + $this->config[$key] = array('*' => $this->config[$key]); + } + $this->config[$key] = array_merge($this->config[$key], $val); + // the full match pattern needs to be last + if (isset($this->config[$key]['*'])) { + $wildcard = $this->config[$key]['*']; + unset($this->config[$key]['*']); + $this->config[$key]['*'] = $wildcard; + } } else { $this->config[$key] = $val; } diff --git a/src/Composer/Downloader/DownloadManager.php b/src/Composer/Downloader/DownloadManager.php index 5c0980725..675b7a051 100644 --- a/src/Composer/Downloader/DownloadManager.php +++ b/src/Composer/Downloader/DownloadManager.php @@ -26,6 +26,7 @@ class DownloadManager private $io; private $preferDist = false; private $preferSource = false; + private $packagePreferences = array(); private $filesystem; private $downloaders = array(); @@ -69,6 +70,19 @@ class DownloadManager return $this; } + /** + * Sets fine tuned preference settings for package level source/dist selection. + * + * @param array $preferences array of preferences by package patterns + * @return DownloadManager + */ + public function setPreferences(array $preferences) + { + $this->packagePreferences = $preferences; + + return $this; + } + /** * Sets whether to output download progress information for all registered * downloaders @@ -184,7 +198,17 @@ class DownloadManager throw new \InvalidArgumentException('Package '.$package.' must have a source or dist specified'); } - if ((!$package->isDev() || $this->preferDist) && !$preferSource) { + if (!$this->preferDist && !$preferSource) { + foreach ($this->packagePreferences as $pattern => $preference) { + $pattern = '{^'.str_replace('*', '.*', $pattern).'$}i'; + if (preg_match($pattern, $package->getName())) { + if ('dist' === $preference || (!$package->isDev() && 'auto' === $preference)) { + $sources = array_reverse($sources); + } + break; + } + } + } elseif ((!$package->isDev() || $this->preferDist) && !$preferSource) { $sources = array_reverse($sources); } diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index da0a9ef63..aeb83f0de 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -383,7 +383,7 @@ class Factory } $dm = new Downloader\DownloadManager($io); - switch ($config->get('preferred-install')) { + switch ($preferred = $config->get('preferred-install')) { case 'dist': $dm->setPreferDist(true); break; @@ -396,6 +396,10 @@ class Factory break; } + if (is_array($preferred)) { + $dm->setPreferences($preferred); + } + $dm->setDownloader('git', new Downloader\GitDownloader($io, $config)); $dm->setDownloader('svn', new Downloader\SvnDownloader($io, $config)); $dm->setDownloader('hg', new Downloader\HgDownloader($io, $config));