From 08cee4c3e986717a42f00d8ab91e17a7eb90fd55 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 12 Mar 2020 15:30:20 +0100 Subject: [PATCH] Implement getProviders equally on all repos --- src/Composer/Repository/ArrayRepository.php | 27 ++++++++++++++ .../Repository/ComposerRepository.php | 37 ++++++++++++++++--- .../Repository/CompositeRepository.php | 14 +++++++ .../Repository/LockArrayRepository.php | 2 +- .../Repository/RepositoryInterface.php | 11 ++++++ src/Composer/Repository/RepositorySet.php | 19 +--------- .../Fixtures/installer/solver-problems.test | 36 ++++++++++-------- 7 files changed, 107 insertions(+), 39 deletions(-) diff --git a/src/Composer/Repository/ArrayRepository.php b/src/Composer/Repository/ArrayRepository.php index f63f80753..69ea0d080 100644 --- a/src/Composer/Repository/ArrayRepository.php +++ b/src/Composer/Repository/ArrayRepository.php @@ -204,6 +204,33 @@ class ArrayRepository implements RepositoryInterface $this->packageMap = null; } + /** + * {@inheritDoc} + */ + public function getProviders($packageName) + { + $result = array(); + + foreach ($this->getPackages() as $candidate) { + if (isset($result[$candidate->getName()])) { + continue; + } + foreach ($candidate->getProvides() as $link) { + if ($packageName === $link->getTarget()) { + $result[$candidate->getName()] = array( + 'name' => $candidate->getName(), + 'description' => $candidate->getDescription(), + 'type' => $candidate->getType(), + 'repository' => $candidate->getSourceUrl() ?: '', + ); + continue 2; + } + } + } + + return $result; + } + protected function createAliasPackage(PackageInterface $package, $alias, $prettyAlias) { return new AliasPackage($package instanceof AliasPackage ? $package->getAliasOf() : $package, $alias, $prettyAlias); diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index e982de5b2..dc455dc8d 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -421,15 +421,40 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito public function getProviders($packageName) { - if (!$this->providersApiUrl) { - // TODO should this return the info based on getPackages in other cases? - return array(); + $this->loadRootServerFile(); + $result = array(); + + if ($this->providersApiUrl) { + $apiResult = $this->httpDownloader->get(str_replace('%package%', $packageName, $this->providersApiUrl), $this->options)->decodeJson(); + + foreach ($apiResult['providers'] as $provider) { + $result[$provider['name']] = $provider; + } + + return $result; + } + + if ($this->hasPartialPackages()) { + foreach ($this->partialPackagesByName as $versions) { + foreach ($versions as $candidate) { + if (isset($result[$candidate['name']]) || !isset($candidate['provide'][$packageName])) { + continue; + } + $result[$candidate['name']] = array( + 'name' => $candidate['name'], + 'description' => isset($candidate['description']) ? $candidate['description'] : '', + 'type' => isset($candidate['type']) ? $candidate['type'] : '', + 'repository' => '', + ); + } + } } - $result = $this->httpDownloader->get(str_replace('%package%', $packageName, $this->providersApiUrl), $this->options)->decodeJson(); + if ($this->packages) { + $result = array_merge($result, parent::getProviders($packageName)); + } - // TODO filter packageName out here? - return $result['providers']; + return $result; } private function getProviderNames() diff --git a/src/Composer/Repository/CompositeRepository.php b/src/Composer/Repository/CompositeRepository.php index 5242da688..acabaffb0 100644 --- a/src/Composer/Repository/CompositeRepository.php +++ b/src/Composer/Repository/CompositeRepository.php @@ -147,6 +147,20 @@ class CompositeRepository implements RepositoryInterface return $packages ? call_user_func_array('array_merge', $packages) : array(); } + /** + * {@inheritdoc} + */ + public function getProviders($packageName) + { + $results = array(); + foreach ($this->repositories as $repository) { + /* @var $repository RepositoryInterface */ + $results[] = $repository->getProviders($packageName); + } + + return $results ? call_user_func_array('array_merge', $results) : array(); + } + /** * {@inheritdoc} */ diff --git a/src/Composer/Repository/LockArrayRepository.php b/src/Composer/Repository/LockArrayRepository.php index 8da3d5915..30bbaa5b2 100644 --- a/src/Composer/Repository/LockArrayRepository.php +++ b/src/Composer/Repository/LockArrayRepository.php @@ -19,7 +19,7 @@ namespace Composer\Repository; * * @author Nils Adermann */ -class LockArrayRepository extends ArrayRepository implements RepositoryInterface +class LockArrayRepository extends ArrayRepository { public function getRepoName() { diff --git a/src/Composer/Repository/RepositoryInterface.php b/src/Composer/Repository/RepositoryInterface.php index 9992778fb..75813c085 100644 --- a/src/Composer/Repository/RepositoryInterface.php +++ b/src/Composer/Repository/RepositoryInterface.php @@ -84,6 +84,17 @@ interface RepositoryInterface extends \Countable */ public function search($query, $mode = 0, $type = null); + /** + * Returns a list of packages providing a given package name + * + * Packages which have the same name as $packageName should not be returned, only those that have a "provide" on it. + * + * @param string $packageName package name which must be provided + * + * @return array[] an array with the provider name as key and value of array('name' => '...', 'description' => '...', 'type' => '...', 'repository' => '...url to source repo if available...') + */ + public function getProviders($packageName); + /** * Returns a name representing this repository to the user * diff --git a/src/Composer/Repository/RepositorySet.php b/src/Composer/Repository/RepositorySet.php index a05906d68..a2efbdc67 100644 --- a/src/Composer/Repository/RepositorySet.php +++ b/src/Composer/Repository/RepositorySet.php @@ -167,23 +167,8 @@ class RepositorySet { $providers = array(); foreach ($this->repositories as $repository) { - if ($repository instanceof ComposerRepository) { - if ($repoProviders = $repository->getProviders($packageName)) { - $providers = array_merge($providers, $repoProviders); - } - } else { - foreach ($repository->getPackages() as $candidate) { - foreach ($candidate->getProvides() as $link) { - if ($packageName === $link->getTarget()) { - $providers[] = array( - 'name' => $candidate->getName(), - 'description' => $candidate->getDescription(), - 'type' => $candidate->getType(), - ); - continue 2; - } - } - } + if ($repoProviders = $repository->getProviders($packageName)) { + $providers = array_merge($providers, $repoProviders); } } diff --git a/tests/Composer/Test/Fixtures/installer/solver-problems.test b/tests/Composer/Test/Fixtures/installer/solver-problems.test index f3905b6fa..005047127 100644 --- a/tests/Composer/Test/Fixtures/installer/solver-problems.test +++ b/tests/Composer/Test/Fixtures/installer/solver-problems.test @@ -47,7 +47,8 @@ Test the error output of solver problems. { "name": "dependency/pkg", "version": "1.0.0" }, { "name": "dependency/unstable-pkg", "version": "1.0.0-dev" }, { "name": "stable-requiree-excluded/pkg", "version": "1.0.1" }, - { "name": "stable-requiree-excluded/pkg", "version": "1.0.0" } + { "name": "stable-requiree-excluded/pkg", "version": "1.0.0" }, + { "name": "api/provider", "description": "Provides the missing API", "version": "1.0.0", "provide": { "missing/provided-api": "1.*" } } ] } ], @@ -59,6 +60,7 @@ Test the error output of solver problems. "package/found5": "2.*", "package/found6": "2.*", "package/found7": "2.*", + "missing/provided-api": "2.*", "conflict/requirer": "2.*", "conflict/requirer2": "2.*", "unstable/package": "2.*", @@ -107,41 +109,45 @@ Updating dependencies Your requirements could not be resolved to an installable set of packages. Problem 1 - - Root composer.json requires unstable/package 2.*, found unstable/package[2.0.0-alpha] but it does not match your minimum-stability. + - Root composer.json requires missing/provided-api 2.*, it could not be found in any version, but the following packages provide it: + - api/provider Provides the missing API + Consider requiring one of these to satisfy the missing/provided-api requirement. Problem 2 - - Root composer.json requires non-existent/pkg, it could not be found in any version, there may be a typo in the package name. + - Root composer.json requires unstable/package 2.*, found unstable/package[2.0.0-alpha] but it does not match your minimum-stability. Problem 3 - - Root composer.json requires stable-requiree-excluded/pkg 1.0.1, found stable-requiree-excluded/pkg[1.0.1] but the package is fixed to 1.0.0 (lock file version) by a partial update and that version does not match. Make sure you whitelist it for update. + - Root composer.json requires non-existent/pkg, it could not be found in any version, there may be a typo in the package name. Problem 4 - - Root composer.json requires linked library lib-xml 1002.* but it has the wrong version installed or is missing from your system, make sure to load the extension providing it. + - Root composer.json requires stable-requiree-excluded/pkg 1.0.1, found stable-requiree-excluded/pkg[1.0.1] but the package is fixed to 1.0.0 (lock file version) by a partial update and that version does not match. Make sure you whitelist it for update. Problem 5 - - Root composer.json requires linked library lib-icu 1001.* but it has the wrong version installed, try upgrading the intl extension. + - Root composer.json requires linked library lib-xml 1002.* but it has the wrong version installed or is missing from your system, make sure to load the extension providing it. Problem 6 - - Root composer.json requires PHP extension ext-xml 1002.* but it has the wrong version (%s) installed. Install or enable PHP's xml extension. + - Root composer.json requires linked library lib-icu 1001.* but it has the wrong version installed, try upgrading the intl extension. Problem 7 - - Root composer.json requires php 1 but your php version (%s) does not satisfy that requirement. + - Root composer.json requires PHP extension ext-xml 1002.* but it has the wrong version (%s) installed. Install or enable PHP's xml extension. Problem 8 + - Root composer.json requires php 1 but your php version (%s) does not satisfy that requirement. + Problem 9 - Root composer.json requires package/found 2.* -> satisfiable by package/found[2.0.0]. - package/found 2.0.0 requires unstable/package2 2.* -> found unstable/package2[2.0.0-alpha] but it does not match your minimum-stability. - Problem 9 + Problem 10 - Root composer.json requires package/found2 2.* -> satisfiable by package/found2[2.0.0]. - package/found2 2.0.0 requires invalid/💩package * -> could not be found, it looks like its name is invalid, "💩" is not allowed in package names. - Problem 10 + Problem 11 - Root composer.json requires package/found3 2.* -> satisfiable by package/found3[2.0.0]. - package/found3 2.0.0 requires unstable/package2 2.* -> found unstable/package2[2.0.0-alpha] but it does not match your minimum-stability. - Problem 11 + Problem 12 - Root composer.json requires package/found4 2.* -> satisfiable by package/found4[2.0.0]. - package/found4 2.0.0 requires non-existent/pkg2 1.* -> could not be found in any version, there may be a typo in the package name. - Problem 12 + Problem 13 - Root composer.json requires package/found6 2.* -> satisfiable by package/found6[2.0.0]. - package/found6 2.0.0 requires stable-requiree-excluded/pkg2 1.0.1 -> found stable-requiree-excluded/pkg2[1.0.0] but it does not match your constraint. - Problem 13 + Problem 14 - Root composer.json requires package/found7 2.* -> satisfiable by package/found7[2.0.0]. - package/found7 2.0.0 requires php-64bit 1.0.1 -> your php-64bit version (%s) does not satisfy that requirement. - Problem 14 + Problem 15 - Root composer.json requires requirer/pkg 1.* -> satisfiable by requirer/pkg[1.0.0]. - requirer/pkg 1.0.0 requires dependency/pkg 1.0.0 -> found dependency/pkg[1.0.0] but it conflicts with your root composer.json require (2.*). - Problem 15 + Problem 16 - requirer/pkg 1.0.0 requires dependency/pkg 1.0.0 -> found dependency/pkg[1.0.0] but it conflicts with your root composer.json require (2.*). - package/found5 2.0.0 requires requirer/pkg 1.* -> satisfiable by requirer/pkg[1.0.0]. - Root composer.json requires package/found5 2.* -> satisfiable by package/found5[2.0.0].