* Jordi Boggiano * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Composer\Repository; use Composer\DependencyResolver\Pool; use Composer\DependencyResolver\PoolBuilder; use Composer\DependencyResolver\Request; use Composer\Package\BasePackage; use Composer\Package\Version\VersionParser; use Composer\Repository\CompositeRepository; use Composer\Repository\PlatformRepository; use Composer\Semver\Constraint\ConstraintInterface; use Composer\Test\DependencyResolver\PoolTest; /** * @author Nils Adermann */ class RepositorySet { /** @var array */ private $rootAliases; /** @var array */ private $rootReferences; /** @var RepositoryInterface[] */ private $repositories = array(); private $acceptableStabilities; private $stabilityFlags; protected $rootRequires; /** @var Pool */ private $pool; public function __construct(array $rootAliases = array(), array $rootReferences = array(), $minimumStability = 'stable', array $stabilityFlags = array(), array $rootRequires = array()) { $this->rootAliases = $rootAliases; $this->rootReferences = $rootReferences; $this->acceptableStabilities = array(); foreach (BasePackage::$stabilities as $stability => $value) { if ($value <= BasePackage::$stabilities[$minimumStability]) { $this->acceptableStabilities[$stability] = $value; } } $this->stabilityFlags = $stabilityFlags; $this->rootRequires = $rootRequires; foreach ($rootRequires as $name => $constraint) { if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) { unset($this->rootRequires[$name]); } } } /** * Adds a repository to this repository set * * The first repos added have a higher priority. As soon as a package is found in any * repository the search for that package ends, and following repos will not be consulted. * * @param RepositoryInterface $repo A package repository */ public function addRepository(RepositoryInterface $repo) { if ($this->pool) { throw new \RuntimeException("Pool has already been created from this repository set, it cannot be modified anymore."); } if ($repo instanceof CompositeRepository) { $repos = $repo->getRepositories(); } else { $repos = array($repo); } foreach ($repos as $repo) { $this->repositories[] = $repo; } } public function isPackageAcceptable($name, $stability) { foreach ((array) $name as $n) { // allow if package matches the global stability requirement and has no exception if (!isset($this->stabilityFlags[$n]) && isset($this->acceptableStabilities[$stability])) { return true; } // allow if package matches the package-specific stability flag if (isset($this->stabilityFlags[$n]) && BasePackage::$stabilities[$stability] <= $this->stabilityFlags[$n]) { return true; } } return false; } /** * Find packages providing or matching a name and optionally meeting a constraint in all repositories * * Returned in the order of repositories, matching priority * * @param string $name * @param ConstraintInterface|null $constraint * @param bool $exactMatch * @return array */ public function findPackages($name, ConstraintInterface $constraint = null, $exactMatch = true) { $packages = array(); foreach ($this->repositories as $repository) { $packages[] = $repository->findPackages($name, $constraint) ?: array(); } $candidates = $packages ? call_user_func_array('array_merge', $packages) : array(); $result = array(); foreach ($candidates as $candidate) { if ($exactMatch && $candidate->getName() !== $name) { continue; } if ($this->isPackageAcceptable($candidate->getNames(), $candidate->getStability())) { $result[] = $candidate; } } return $candidates; } /** * Create a pool for dependency resolution from the packages in this repository set. * * @return Pool */ public function createPool(Request $request) { $poolBuilder = new PoolBuilder(array($this, 'isPackageAcceptable'), $this->rootRequires); return $this->pool = $poolBuilder->buildPool($this->repositories, $this->rootAliases, $this->rootReferences, $request); } // TODO unify this with above in some simpler version without "request"? public function createPoolForPackage($packageName) { return $this->createPoolForPackages(array($packageName)); } public function createPoolForPackages($packageNames) { $request = new Request(); foreach ($packageNames as $packageName) { $request->install($packageName); } return $this->createPool($request); } /** * Access the pool object after it has been created, relevant for plugins which need to read info from the pool * @return Pool */ public function getPool() { return $this->pool; } }