diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php index a7efca100..eed4c5043 100644 --- a/src/Composer/DependencyResolver/Problem.php +++ b/src/Composer/DependencyResolver/Problem.php @@ -94,11 +94,19 @@ class Problem } } + return self::formatDeduplicatedRules($reasons, ' ', $repositorySet, $request, $pool, $isVerbose, $installedMap, $learnedPool); + } + + /** + * @internal + */ + public static function formatDeduplicatedRules($rules, $indent, RepositorySet $repositorySet, Request $request, Pool $pool, $isVerbose, array $installedMap = array(), array $learnedPool = array()) + { $messages = array(); $templates = array(); $parser = new VersionParser; $deduplicatableRuleTypes = array(Rule::RULE_PACKAGE_REQUIRES, Rule::RULE_PACKAGE_CONFLICT); - foreach ($reasons as $rule) { + foreach ($rules as $rule) { $message = $rule->getPrettyString($repositorySet, $request, $pool, $isVerbose, $installedMap, $learnedPool); if (in_array($rule->getReason(), $deduplicatableRuleTypes, true) && preg_match('{^(?P\S+) (?P\S+) (?Prequires|conflicts)}', $message, $m)) { $template = preg_replace('{^\S+ \S+ }', '%s%s ', $message); @@ -130,7 +138,7 @@ class Problem } } - return "\n - ".implode("\n - ", $result); + return "\n$indent- ".implode("\n$indent- ", $result); } public function isCausedByLock(RepositorySet $repositorySet, Request $request, Pool $pool) diff --git a/src/Composer/DependencyResolver/Rule.php b/src/Composer/DependencyResolver/Rule.php index 5cee6c2e3..8ba9756d6 100644 --- a/src/Composer/DependencyResolver/Rule.php +++ b/src/Composer/DependencyResolver/Rule.php @@ -170,14 +170,6 @@ abstract class Rule { $literals = $this->getLiterals(); - $ruleText = ''; - foreach ($literals as $i => $literal) { - if ($i != 0) { - $ruleText .= '|'; - } - $ruleText .= $pool->literalToPrettyString($literal, $installedMap); - } - switch ($this->getReason()) { case self::RULE_ROOT_REQUIRE: $packageName = $this->reasonData['packageName']; @@ -272,19 +264,33 @@ abstract class Rule return 'You can only install one version of a package, so only one of these can be installed: ' . $this->formatPackagesUnique($pool, $literals, $isVerbose) . '.'; case self::RULE_LEARNED: if (isset($learnedPool[$this->reasonData])) { - $learnedString = ', learned rules:'."\n - "; - $reasons = array(); - foreach ($learnedPool[$this->reasonData] as $learnedRule) { - $reason = $learnedRule->getPrettyString($repositorySet, $request, $pool, $installedMap, $learnedPool); - if ($reason !== '') { - $reasons[] = $reason; - } - } - $learnedString .= implode("\n - ", array_unique($reasons)); + $learnedString = ', learned rules:' . Problem::formatDeduplicatedRules($learnedPool[$this->reasonData], ' ', $repositorySet, $request, $pool, $installedMap, $learnedPool); } else { $learnedString = ' (reasoning unavailable)'; } + if (count($literals) === 1) { + $ruleText = $pool->literalToPrettyString($literals[0], $installedMap); + } else { + $groups = array(); + foreach ($literals as $literal) { + $package = $pool->literalToPackage($literal); + if (isset($installedMap[$package->id])) { + $group = $literal > 0 ? 'keep' : 'remove'; + } else { + $group = $literal > 0 ? 'install' : 'don\'t install'; + } + + $groups[$group][] = $this->deduplicateMasterAlias($package); + } + $ruleTexts = array(); + foreach ($groups as $group => $packages) { + $ruleTexts[] = $group . (count($packages) > 1 ? ' one of' : '').' ' . $this->formatPackagesUnique($pool, $packages, $isVerbose); + } + + $ruleText = implode(' | ', $ruleTexts); + } + return 'Conclusion: '.$ruleText.$learnedString; case self::RULE_PACKAGE_ALIAS: $aliasPackage = $pool->literalToPackage($literals[0]); @@ -296,6 +302,14 @@ abstract class Rule return $aliasPackage->getPrettyString() .' is an alias of '.$package->getPrettyString().' and thus requires it to be installed too.'; default: + $ruleText = ''; + foreach ($literals as $i => $literal) { + if ($i != 0) { + $ruleText .= '|'; + } + $ruleText .= $pool->literalToPrettyString($literal, $installedMap); + } + return '('.$ruleText.')'; } }