diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php index 6d94b068b..9d4405330 100644 --- a/src/Composer/DependencyResolver/Problem.php +++ b/src/Composer/DependencyResolver/Problem.php @@ -276,27 +276,19 @@ class Problem // check if the package is found when bypassing stability checks if ($packages = $repositorySet->findPackages($packageName, $constraint, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES)) { + // we must first verify if a valid package would be found in a lower priority repository + if ($allReposPackages = $repositorySet->findPackages($packageName, $constraint, RepositorySet::ALLOW_SHADOWED_REPOSITORIES)) { + return self::computeCheckForLowerPrioRepo($isVerbose, $packageName, $constraint, $packages, $allReposPackages, 'minimum-stability'); + } + return array("- Root composer.json requires $packageName".self::constraintToText($constraint) . ', ', 'found '.self::getPackageList($packages, $isVerbose).' but '.(self::hasMultipleNames($packages) ? 'these do' : 'it does').' not match your minimum-stability.'); } - // check if the package is found when bypassing the constraint check - if ($packages = $repositorySet->findPackages($packageName, null)) { + // check if the package is found when bypassing the constraint and stability checks + if ($packages = $repositorySet->findPackages($packageName, null, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES)) { // we must first verify if a valid package would be found in a lower priority repository if ($allReposPackages = $repositorySet->findPackages($packageName, $constraint, RepositorySet::ALLOW_SHADOWED_REPOSITORIES)) { - $higherRepoPackages = $repositorySet->findPackages($packageName, null); - $nextRepoPackages = array(); - $nextRepo = null; - - foreach ($allReposPackages as $package) { - if ($nextRepo === null || $nextRepo === $package->getRepository()) { - $nextRepoPackages[] = $package; - $nextRepo = $package->getRepository(); - } else { - break; - } - } - - return array("- Root composer.json requires $packageName".self::constraintToText($constraint) . ', it is ', 'satisfiable by '.self::getPackageList($nextRepoPackages, $isVerbose).' from '.$nextRepo->getRepoName().' but '.self::getPackageList($higherRepoPackages, $isVerbose).' from '.reset($higherRepoPackages)->getRepository()->getRepoName().' has higher repository priority. The packages with higher priority do not match your constraint and are therefore not installable. See https://getcomposer.org/repoprio for details and assistance.'); + return self::computeCheckForLowerPrioRepo($isVerbose, $packageName, $constraint, $packages, $allReposPackages, 'constraint'); } return array("- Root composer.json requires $packageName".self::constraintToText($constraint) . ', ', 'found '.self::getPackageList($packages, $isVerbose).' but '.(self::hasMultipleNames($packages) ? 'these do' : 'it does').' not match the constraint.'); @@ -396,6 +388,24 @@ class Problem return false; } + private static function computeCheckForLowerPrioRepo($isVerbose, $packageName, $constraint, array $higherRepoPackages, array $allReposPackages, $reason) + { + $nextRepoPackages = array(); + $nextRepo = null; + + foreach ($allReposPackages as $package) { + if ($nextRepo === null || $nextRepo === $package->getRepository()) { + $nextRepoPackages[] = $package; + $nextRepo = $package->getRepository(); + } else { + break; + } + } + + return array("- Root composer.json requires $packageName".self::constraintToText($constraint) . ', it is ', 'satisfiable by '.self::getPackageList($nextRepoPackages, $isVerbose).' from '.$nextRepo->getRepoName().' but '.self::getPackageList($higherRepoPackages, $isVerbose).' from '.reset($higherRepoPackages)->getRepository()->getRepoName().' has higher repository priority. The packages with higher priority do not match your '.$reason.' and are therefore not installable. See https://getcomposer.org/repoprio for details and assistance.'); + + } + /** * Turns a constraint into text usable in a sentence describing a request * diff --git a/src/Composer/Repository/RepositorySet.php b/src/Composer/Repository/RepositorySet.php index 9417dec97..04db0becd 100644 --- a/src/Composer/Repository/RepositorySet.php +++ b/src/Composer/Repository/RepositorySet.php @@ -193,7 +193,7 @@ class RepositorySet } } - return $candidates; + return $result; } public function getProviders($packageName) diff --git a/tests/Composer/Test/Fixtures/installer/repositories-priorities4.test b/tests/Composer/Test/Fixtures/installer/repositories-priorities4.test new file mode 100644 index 000000000..9ef597daa --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/repositories-priorities4.test @@ -0,0 +1,59 @@ +--TEST-- +Packages found in a higher priority repository take precedence even if they are not found in the requested version case #2 +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { + "name": "ruflin/elastica", + "version": "dev-outdated-branch" + } + ] + }, + { + "type": "package", + "package": [ + { + "name": "friendsofsymfony/elastica-bundle", + "version": "dev-foobar-master", + "require": { + "ruflin/elastica": "2.*" + } + } + ] + }, + { + "type": "package", + "package": [ + { + "name": "ruflin/elastica", + "version": "2.0.0" + }, + { + "name": "ruflin/elastica", + "version": "2.0.1" + } + ] + } + ], + "require": { + "friendsofsymfony/elastica-bundle": "dev-foobar-master" + } +} + +--RUN-- +update +--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 friendsofsymfony/elastica-bundle dev-foobar-master -> satisfiable by friendsofsymfony/elastica-bundle[dev-foobar-master]. + - friendsofsymfony/elastica-bundle dev-foobar-master requires ruflin/elastica 2.* -> satisfiable by ruflin/elastica[2.0.0, 2.0.1] from package repo (defining 2 packages) but ruflin/elastica[dev-outdated-branch] from package repo (defining 1 package) has higher repository priority. The packages with higher priority do not match your constraint and are therefore not installable. See https://getcomposer.org/repoprio for details and assistance. + +--EXPECT-- +--EXPECT-EXIT-CODE-- +2 diff --git a/tests/Composer/Test/Fixtures/installer/repositories-priorities5.test b/tests/Composer/Test/Fixtures/installer/repositories-priorities5.test new file mode 100644 index 000000000..7a196988e --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/repositories-priorities5.test @@ -0,0 +1,35 @@ +--TEST-- +Packages found in a higher priority repository take precedence even if they are not found in the requested version case #3 +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "foo/a", "version": "2.0.0-dev" } + ] + }, + { + "type": "package", + "package": [ + { "name": "foo/a", "version": "2.0.0" } + ] + } + ], + "require": { + "foo/a": "2.*" + } +} +--RUN-- +update +--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/a 2.*, it is satisfiable by foo/a[2.0.0] from package repo (defining 1 package) but foo/a[2.0.0-dev] from package repo (defining 1 package) has higher repository priority. The packages with higher priority do not match your minimum-stability and are therefore not installable. See https://getcomposer.org/repoprio for details and assistance. + +--EXPECT-- +--EXPECT-EXIT-CODE-- +2