From 8a41f1a5ca1378845dd0925d74648fd24f7b5c5d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 30 Jan 2020 13:19:54 +0100 Subject: [PATCH] Allow providers which are selected to be installed in place of existing packages which do not satisfy requirements, fixes #6753 --- src/Composer/DependencyResolver/Pool.php | 24 +------- ...packages-can-be-installed-if-selected.test | 36 ++++++++++++ ...her-with-provided-if-both-installable.json | 34 ++++++++++++ ...-can-not-be-installed-unless-selected.test | 55 +++++++++++++++++++ 4 files changed, 128 insertions(+), 21 deletions(-) create mode 100644 tests/Composer/Test/Fixtures/installer/provider-packages-can-be-installed-if-selected.test create mode 100644 tests/Composer/Test/Fixtures/installer/provider-packages-can-be-installed-together-with-provided-if-both-installable.json create mode 100644 tests/Composer/Test/Fixtures/installer/provider-packages-can-not-be-installed-unless-selected.test diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index 69a5b2cc2..1e1100b15 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -27,7 +27,6 @@ use Composer\Package\PackageInterface; */ class Pool implements \Countable { - const MATCH_NAME = -1; const MATCH_NONE = 0; const MATCH = 1; const MATCH_PROVIDE = 2; @@ -117,27 +116,15 @@ class Pool implements \Countable $candidates = $this->packageByName[$name]; } - $matches = $provideMatches = array(); - $nameMatch = false; + $matches = array(); foreach ($candidates as $candidate) { switch ($this->match($candidate, $name, $constraint)) { case self::MATCH_NONE: break; - case self::MATCH_NAME: - $nameMatch = true; - break; - case self::MATCH: - $nameMatch = true; - $matches[] = $candidate; - break; - case self::MATCH_PROVIDE: - $provideMatches[] = $candidate; - break; - case self::MATCH_REPLACE: $matches[] = $candidate; break; @@ -147,12 +134,7 @@ class Pool implements \Countable } } - // if a package with the required name exists, we ignore providers - if ($nameMatch) { - return $matches; - } - - return array_merge($matches, $provideMatches); + return $matches; } public function literalToPackage($literal) @@ -196,7 +178,7 @@ class Pool implements \Countable return self::MATCH; } - return self::MATCH_NAME; + return self::MATCH_NONE; } $provides = $candidate->getProvides(); diff --git a/tests/Composer/Test/Fixtures/installer/provider-packages-can-be-installed-if-selected.test b/tests/Composer/Test/Fixtures/installer/provider-packages-can-be-installed-if-selected.test new file mode 100644 index 000000000..be425010c --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/provider-packages-can-be-installed-if-selected.test @@ -0,0 +1,36 @@ +--TEST-- +Test that providers can be installed if they are selected and the package they provide is not installable +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { + "name": "foo/polyfill", + "provide": { + "foo/standard": "1.0.0" + }, + "version": "1.0.0" + }, + { + "name": "foo/standard", + "require": { + "foo/does-not-exist": "1.0.0" + }, + "version": "1.0.0" + } + ] + } + ], + "require": { + "foo/standard": "1.0.0", + "foo/polyfill": "1.0.0" + } +} + +--RUN-- +update + +--EXPECT-- +Installing foo/polyfill (1.0.0) diff --git a/tests/Composer/Test/Fixtures/installer/provider-packages-can-be-installed-together-with-provided-if-both-installable.json b/tests/Composer/Test/Fixtures/installer/provider-packages-can-be-installed-together-with-provided-if-both-installable.json new file mode 100644 index 000000000..9abe90dd8 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/provider-packages-can-be-installed-together-with-provided-if-both-installable.json @@ -0,0 +1,34 @@ +--TEST-- +Test that providers can be installed in conjunction with the package they provide if they are selected and the package they provide is also installable +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { + "name": "foo/polyfill", + "provide": { + "foo/standard": "1.0.0" + }, + "version": "1.0.0" + }, + { + "name": "foo/standard", + "version": "1.0.0" + } + ] + } + ], + "require": { + "foo/standard": "1.0.0", + "foo/polyfill": "1.0.0" + } +} + +--RUN-- +update + +--EXPECT-- +Installing foo/standard (1.0.0) +Installing foo/polyfill (1.0.0) diff --git a/tests/Composer/Test/Fixtures/installer/provider-packages-can-not-be-installed-unless-selected.test b/tests/Composer/Test/Fixtures/installer/provider-packages-can-not-be-installed-unless-selected.test new file mode 100644 index 000000000..85347b4e6 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/provider-packages-can-not-be-installed-unless-selected.test @@ -0,0 +1,55 @@ +--TEST-- +Test that providers can not be installed if they are not selected +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { + "name": "foo/polyfill", + "provide": { + "foo/standard": "1.0.0" + }, + "version": "1.0.0" + }, + { + "name": "foo/standard", + "require": { + "foo/does-not-exist": "1.0.0" + }, + "version": "1.0.0" + } + ] + } + ], + "require": { + "foo/standard": "1.0.0" + } +} + +--RUN-- +update + +--EXPECT-EXIT-CODE-- +2 + +--EXPECT-OUTPUT-- +Loading composer repositories with package information +Updating dependencies +Your requirements could not be resolved to an installable set of packages. + + Problem 1 + - Root composer.json requires foo/standard 1.0.0 -> satisfiable by foo/standard[1.0.0]. + - foo/standard 1.0.0 requires foo/does-not-exist 1.0.0 -> no matching package found. + +Potential causes: + - A typo in the package name + - The package is not available in a stable-enough version according to your minimum-stability setting + see for more details. + - It's a private package and you forgot to add a custom repository to find it + +Read for further common problems. + +--EXPECT-- +