1
0
Fork 0

Improve solver error reporting, fixes #5086, fixes #2575, fixes #2661

pull/5120/head
Jordi Boggiano 2016-03-27 18:39:36 +01:00
parent 37a1e12672
commit 623c0dcda7
4 changed files with 44 additions and 15 deletions

View File

@ -176,27 +176,32 @@ class Pool implements \Countable
* packages must match or null to return all
* @param bool $mustMatchName Whether the name of returned packages
* must match the given name
* @param bool $bypassFilters If enabled, filterRequires and stability matching is ignored
* @return PackageInterface[] A set of packages
*/
public function whatProvides($name, ConstraintInterface $constraint = null, $mustMatchName = false)
public function whatProvides($name, ConstraintInterface $constraint = null, $mustMatchName = false, $bypassFilters = false)
{
if ($bypassFilters) {
return $this->computeWhatProvides($name, $constraint, $mustMatchName, true);
}
$key = ((int) $mustMatchName).$constraint;
if (isset($this->providerCache[$name][$key])) {
return $this->providerCache[$name][$key];
}
return $this->providerCache[$name][$key] = $this->computeWhatProvides($name, $constraint, $mustMatchName);
return $this->providerCache[$name][$key] = $this->computeWhatProvides($name, $constraint, $mustMatchName, $bypassFilters);
}
/**
* @see whatProvides
*/
private function computeWhatProvides($name, $constraint, $mustMatchName = false)
private function computeWhatProvides($name, $constraint, $mustMatchName = false, $bypassFilters = false)
{
$candidates = array();
foreach ($this->providerRepos as $repo) {
foreach ($repo->whatProvides($this, $name) as $candidate) {
foreach ($repo->whatProvides($this, $name, $bypassFilters) as $candidate) {
$candidates[] = $candidate;
if ($candidate->id < 1) {
$candidate->setId($this->id++);
@ -228,13 +233,13 @@ class Pool implements \Countable
$aliasOfCandidate = $candidate->getAliasOf();
}
if ($this->whitelist !== null && (
if ($this->whitelist !== null && !$bypassFilters && (
(!($candidate instanceof AliasPackage) && !isset($this->whitelist[$candidate->id])) ||
($candidate instanceof AliasPackage && !isset($this->whitelist[$aliasOfCandidate->id]))
)) {
continue;
}
switch ($this->match($candidate, $name, $constraint)) {
switch ($this->match($candidate, $name, $constraint, $bypassFilters)) {
case self::MATCH_NONE:
break;
@ -317,14 +322,14 @@ class Pool implements \Countable
* @param ConstraintInterface $constraint The constraint to verify
* @return int One of the MATCH* constants of this class or 0 if there is no match
*/
private function match($candidate, $name, ConstraintInterface $constraint = null)
private function match($candidate, $name, ConstraintInterface $constraint = null, $bypassFilters)
{
$candidateName = $candidate->getName();
$candidateVersion = $candidate->getVersion();
$isDev = $candidate->getStability() === 'dev';
$isAlias = $candidate instanceof AliasPackage;
if (!$isDev && !$isAlias && isset($this->filterRequires[$name])) {
if (!$bypassFilters && !$isDev && !$isAlias && isset($this->filterRequires[$name])) {
$requireFilter = $this->filterRequires[$name];
} else {
$requireFilter = new EmptyConstraint;

View File

@ -129,11 +129,15 @@ class Problem
return "\n - The requested package ".$job['packageName'].' could not be found, it looks like its name is invalid, "'.$illegalChars.'" is not allowed in package names.';
}
if (!$this->pool->whatProvides($job['packageName'])) {
return "\n - The requested package ".$job['packageName'].' could not be found in any version, there may be a typo in the package name.';
if ($providers = $this->pool->whatProvides($job['packageName'], $job['constraint'], true, true)) {
return "\n - The requested package ".$job['packageName'].$this->constraintToText($job['constraint']).' is satisfiable by '.$this->getPackageList($providers).' but those are rejected by your minimum-stability.';
}
return "\n - The requested package ".$job['packageName'].$this->constraintToText($job['constraint']).' could not be found.';
if ($providers = $this->pool->whatProvides($job['packageName'], null, true, true)) {
return "\n - The requested package ".$job['packageName'].$this->constraintToText($job['constraint']).' exists as '.$this->getPackageList($providers).' but those are rejected by your constraint.';
}
return "\n - The requested package ".$job['packageName'].' could not be found in any version, there may be a typo in the package name.';
}
}

View File

@ -230,6 +230,10 @@ class Rule
return $text . ' -> the requested linked library '.$lib.' has the wrong version installed or is missing from your system, make sure to have the extension providing it.';
} else {
if ($providers = $pool->whatProvides($targetName, $this->reasonData->getConstraint(), true, true)) {
return $text . ' -> satisfiable by ' . $this->formatPackagesUnique($pool, $providers) .' but these conflict with your requirements or minimum-stability';
}
return $text . ' -> no matching package found.';
}
}

View File

@ -268,9 +268,14 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
}
}
public function whatProvides(Pool $pool, $name)
/**
* @param Pool $pool
* @param string $name package name
* @param bool $bypassFilters If set to true, this bypasses the stability filtering, and forces a recompute without cache
*/
public function whatProvides(Pool $pool, $name, $bypassFilters = false)
{
if (isset($this->providers[$name])) {
if (isset($this->providers[$name]) && !$bypassFilters) {
return $this->providers[$name];
}
@ -354,7 +359,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
}
}
} else {
if (!$pool->isPackageAcceptable(strtolower($version['name']), VersionParser::parseStability($version['version']))) {
if (!$bypassFilters && !$pool->isPackageAcceptable(strtolower($version['name']), VersionParser::parseStability($version['version']))) {
continue;
}
@ -396,7 +401,18 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
}
}
return $this->providers[$name];
$result = $this->providers[$name];
// clean up the cache because otherwise using this puts the repo in an inconsistent state with a polluted unfiltered cache
// which is likely not an issue but might cause hard to track behaviors depending on how the repo is used
if ($bypassFilters) {
foreach ($this->providers[$name] as $uid => $provider) {
unset($this->providersByUid[$uid]);
}
unset($this->providers[$name]);
}
return $result;
}
/**