RepositorySet.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Repository;
  12. use Composer\DependencyResolver\Pool;
  13. use Composer\DependencyResolver\PoolBuilder;
  14. use Composer\DependencyResolver\Request;
  15. use Composer\Package\BasePackage;
  16. use Composer\Package\Version\VersionParser;
  17. use Composer\Repository\CompositeRepository;
  18. use Composer\Repository\PlatformRepository;
  19. use Composer\Repository\LockArrayRepository;
  20. use Composer\Repository\InstalledRepositoryInterface;
  21. use Composer\Semver\Constraint\ConstraintInterface;
  22. use Composer\Package\Version\StabilityFilter;
  23. /**
  24. * @author Nils Adermann <naderman@naderman.de>
  25. */
  26. class RepositorySet
  27. {
  28. /** @var array */
  29. private $rootAliases;
  30. /** @var array */
  31. private $rootReferences;
  32. /** @var RepositoryInterface[] */
  33. private $repositories = array();
  34. private $acceptableStabilities;
  35. private $stabilityFlags;
  36. protected $rootRequires;
  37. /** @var Pool */
  38. private $pool;
  39. public function __construct(array $rootAliases = array(), array $rootReferences = array(), $minimumStability = 'stable', array $stabilityFlags = array(), array $rootRequires = array())
  40. {
  41. $this->rootAliases = $rootAliases;
  42. $this->rootReferences = $rootReferences;
  43. $this->acceptableStabilities = array();
  44. foreach (BasePackage::$stabilities as $stability => $value) {
  45. if ($value <= BasePackage::$stabilities[$minimumStability]) {
  46. $this->acceptableStabilities[$stability] = $value;
  47. }
  48. }
  49. $this->stabilityFlags = $stabilityFlags;
  50. $this->rootRequires = $rootRequires;
  51. foreach ($rootRequires as $name => $constraint) {
  52. if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) {
  53. unset($this->rootRequires[$name]);
  54. }
  55. }
  56. }
  57. /**
  58. * Adds a repository to this repository set
  59. *
  60. * The first repos added have a higher priority. As soon as a package is found in any
  61. * repository the search for that package ends, and following repos will not be consulted.
  62. *
  63. * @param RepositoryInterface $repo A package repository
  64. */
  65. public function addRepository(RepositoryInterface $repo)
  66. {
  67. if ($this->pool) {
  68. throw new \RuntimeException("Pool has already been created from this repository set, it cannot be modified anymore.");
  69. }
  70. if ($repo instanceof CompositeRepository) {
  71. $repos = $repo->getRepositories();
  72. } else {
  73. $repos = array($repo);
  74. }
  75. foreach ($repos as $repo) {
  76. $this->repositories[] = $repo;
  77. }
  78. }
  79. /**
  80. * Find packages providing or matching a name and optionally meeting a constraint in all repositories
  81. *
  82. * Returned in the order of repositories, matching priority
  83. *
  84. * @param string $name
  85. * @param ConstraintInterface|null $constraint
  86. * @param bool $exactMatch if set to false, packages which replace/provide the given name might be returned as well even if they do not match the name exactly
  87. * @param bool $ignoreStability if set to true, packages are returned even though their stability does not match the required stability
  88. * @return array
  89. */
  90. public function findPackages($name, ConstraintInterface $constraint = null, $exactMatch = true, $ignoreStability = false)
  91. {
  92. $packages = array();
  93. foreach ($this->repositories as $repository) {
  94. $packages[] = $repository->findPackages($name, $constraint) ?: array();
  95. }
  96. $candidates = $packages ? call_user_func_array('array_merge', $packages) : array();
  97. $result = array();
  98. foreach ($candidates as $candidate) {
  99. if ($exactMatch && $candidate->getName() !== $name) {
  100. continue;
  101. }
  102. if (!$ignoreStability && $this->isPackageAcceptable($candidate->getNames(), $candidate->getStability())) {
  103. $result[] = $candidate;
  104. }
  105. }
  106. return $candidates;
  107. }
  108. public function isPackageAcceptable($names, $stability)
  109. {
  110. return StabilityFilter::isPackageAcceptable($this->acceptableStabilities, $this->stabilityFlags, $names, $stability);
  111. }
  112. /**
  113. * Create a pool for dependency resolution from the packages in this repository set.
  114. *
  115. * @return Pool
  116. */
  117. public function createPool(Request $request)
  118. {
  119. $poolBuilder = new PoolBuilder($this->acceptableStabilities, $this->stabilityFlags, $this->rootAliases, $this->rootReferences, $this->rootRequires);
  120. foreach ($this->repositories as $repo) {
  121. if ($repo instanceof InstalledRepositoryInterface) {
  122. throw new \LogicException('The pool can not accept packages from an installed repository');
  123. }
  124. }
  125. return $this->pool = $poolBuilder->buildPool($this->repositories, $request);
  126. }
  127. // TODO unify this with above in some simpler version without "request"?
  128. public function createPoolForPackage($packageName, LockArrayRepository $lockedRepo = null)
  129. {
  130. return $this->createPoolForPackages(array($packageName), $lockedRepo);
  131. }
  132. public function createPoolForPackages($packageNames, LockArrayRepository $lockedRepo = null)
  133. {
  134. $request = new Request($lockedRepo);
  135. foreach ($packageNames as $packageName) {
  136. $request->requireName($packageName);
  137. }
  138. return $this->createPool($request);
  139. }
  140. /**
  141. * Access the pool object after it has been created, relevant for plugins which need to read info from the pool
  142. * @return Pool
  143. */
  144. public function getPool()
  145. {
  146. return $this->pool;
  147. }
  148. }