-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
SolverProblemsException.php
150 lines (123 loc) · 5.54 KB
/
SolverProblemsException.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\DependencyResolver;
use Composer\Util\IniHelper;
use Composer\Repository\RepositorySet;
/**
* @author Nils Adermann <naderman@naderman.de>
*
* @method self::ERROR_DEPENDENCY_RESOLUTION_FAILED getCode()
*/
class SolverProblemsException extends \RuntimeException
{
public const ERROR_DEPENDENCY_RESOLUTION_FAILED = 2;
/** @var Problem[] */
protected $problems;
/** @var array<Rule[]> */
protected $learnedPool;
/**
* @param Problem[] $problems
* @param array<Rule[]> $learnedPool
*/
public function __construct(array $problems, array $learnedPool)
{
$this->problems = $problems;
$this->learnedPool = $learnedPool;
parent::__construct('Failed resolving dependencies with '.count($problems).' problems, call getPrettyString to get formatted details', self::ERROR_DEPENDENCY_RESOLUTION_FAILED);
}
/**
* @param bool $isVerbose
* @param bool $isDevExtraction
* @return string
*/
public function getPrettyString(RepositorySet $repositorySet, Request $request, Pool $pool, bool $isVerbose, bool $isDevExtraction = false): string
{
$installedMap = $request->getPresentMap(true);
$missingExtensions = array();
$isCausedByLock = false;
$problems = array();
foreach ($this->problems as $problem) {
$problems[] = $problem->getPrettyString($repositorySet, $request, $pool, $isVerbose, $installedMap, $this->learnedPool)."\n";
$missingExtensions = array_merge($missingExtensions, $this->getExtensionProblems($problem->getReasons()));
$isCausedByLock = $isCausedByLock || $problem->isCausedByLock($repositorySet, $request, $pool);
}
$i = 1;
$text = "\n";
foreach (array_unique($problems) as $problem) {
$text .= " Problem ".($i++).$problem;
}
$hints = array();
if (!$isDevExtraction && (strpos($text, 'could not be found') || strpos($text, 'no matching package found'))) {
$hints[] = "Potential causes:\n - A typo in the package name\n - The package is not available in a stable-enough version according to your minimum-stability setting\n see <https://getcomposer.org/doc/04-schema.md#minimum-stability> for more details.\n - It's a private package and you forgot to add a custom repository to find it\n\nRead <https://getcomposer.org/doc/articles/troubleshooting.md> for further common problems.";
}
if (!empty($missingExtensions)) {
$hints[] = $this->createExtensionHint($missingExtensions);
}
if ($isCausedByLock && !$isDevExtraction && !$request->getUpdateAllowTransitiveRootDependencies()) {
$hints[] = "Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.";
}
if (strpos($text, 'found composer-plugin-api[2.0.0] but it does not match') && strpos($text, '- ocramius/package-versions')) {
$hints[] = "<warning>ocramius/package-versions only provides support for Composer 2 in 1.8+, which requires PHP 7.4.</warning>\nIf you can not upgrade PHP you can require <info>composer/package-versions-deprecated</info> to resolve this with PHP 7.0+.";
}
if (!class_exists('PHPUnit\Framework\TestCase', false)) {
if (strpos($text, 'found composer-plugin-api[2.0.0] but it does not match')) {
$hints[] = "You are using Composer 2, which some of your plugins seem to be incompatible with. Make sure you update your plugins or report a plugin-issue to ask them to support Composer 2.";
}
}
if ($hints) {
$text .= "\n" . implode("\n\n", $hints);
}
return $text;
}
/**
* @return Problem[]
*/
public function getProblems(): array
{
return $this->problems;
}
/**
* @param string[] $missingExtensions
* @return string
*/
private function createExtensionHint(array $missingExtensions): string
{
$paths = IniHelper::getAll();
if (count($paths) === 1 && empty($paths[0])) {
return '';
}
$ignoreExtensionsArguments = implode(" ", array_map(function ($extension) {
return "--ignore-platform-req=$extension";
}, $missingExtensions));
$text = "To enable extensions, verify that they are enabled in your .ini files:\n - ";
$text .= implode("\n - ", $paths);
$text .= "\nYou can also run `php --ini` in a terminal to see which files are used by PHP in CLI mode.";
$text .= "\nAlternatively, you can run Composer with `$ignoreExtensionsArguments` to temporarily ignore these required extensions.";
return $text;
}
/**
* @param Rule[][] $reasonSets
* @return string[]
*/
private function getExtensionProblems(array $reasonSets): array
{
$missingExtensions = array();
foreach ($reasonSets as $reasonSet) {
foreach ($reasonSet as $rule) {
$required = $rule->getRequiredPackage();
if (null !== $required && 0 === strpos($required, 'ext-')) {
$missingExtensions[$required] = 1;
}
}
}
return array_keys($missingExtensions);
}
}