1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of tenside/core. |
5
|
|
|
* |
6
|
|
|
* (c) Christian Schiffler <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
* |
11
|
|
|
* This project is provided in good faith and hope to be usable by anyone. |
12
|
|
|
* |
13
|
|
|
* @package tenside/core |
14
|
|
|
* @author Christian Schiffler <[email protected]> |
15
|
|
|
* @copyright 2015 Christian Schiffler <[email protected]> |
16
|
|
|
* @license https://github.com/tenside/core/blob/master/LICENSE MIT |
17
|
|
|
* @link https://github.com/tenside/core |
18
|
|
|
* @filesource |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
namespace Tenside\Core\Composer; |
22
|
|
|
|
23
|
|
|
use Composer\Composer; |
24
|
|
|
use Composer\DependencyResolver\DefaultPolicy; |
25
|
|
|
use Composer\DependencyResolver\Operation\OperationInterface; |
26
|
|
|
use Composer\DependencyResolver\Pool; |
27
|
|
|
use Composer\DependencyResolver\Request; |
28
|
|
|
use Composer\DependencyResolver\Solver; |
29
|
|
|
use Composer\DependencyResolver\SolverProblemsException; |
30
|
|
|
use Composer\Package\Link; |
31
|
|
|
use Composer\Package\PackageInterface; |
32
|
|
|
use Composer\Package\RootPackageInterface; |
33
|
|
|
use Composer\Repository\CompositeRepository; |
34
|
|
|
use Composer\Repository\InstalledArrayRepository; |
35
|
|
|
use Composer\Repository\PlatformRepository; |
36
|
|
|
use Composer\Semver\Constraint\Constraint; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* This class is resolving dependencies. |
40
|
|
|
*/ |
41
|
|
|
class SolverRunner |
42
|
|
|
{ |
43
|
|
|
/** |
44
|
|
|
* The composer instance. |
45
|
|
|
* |
46
|
|
|
* @var Composer |
47
|
|
|
*/ |
48
|
|
|
private $composer; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* The root package. |
52
|
|
|
* |
53
|
|
|
* @var RootPackageInterface |
54
|
|
|
*/ |
55
|
|
|
private $package; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* The built pool. |
59
|
|
|
* |
60
|
|
|
* @var Pool |
61
|
|
|
*/ |
62
|
|
|
private $pool; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* The platform repository. |
66
|
|
|
* |
67
|
|
|
* @var PlatformRepository |
68
|
|
|
*/ |
69
|
|
|
private $platform; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* The repository reflecting the current installation. |
73
|
|
|
* |
74
|
|
|
* @var CompositeRepository |
75
|
|
|
*/ |
76
|
|
|
private $installed; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* Create a new instance. |
80
|
|
|
* |
81
|
|
|
* @param Composer $composer The composer instance. |
82
|
|
|
*/ |
83
|
|
|
public function __construct(Composer $composer) |
84
|
|
|
{ |
85
|
|
|
// clone root package to have one in the installed repo that does not require anything |
86
|
|
|
// we don't want it to be uninstallable, but its requirements should not conflict |
87
|
|
|
// with the lock file for example |
88
|
|
|
$this->composer = $composer; |
89
|
|
|
$this->package = $this->composer->getPackage(); |
90
|
|
|
$installedRoot = clone $this->package; |
91
|
|
|
$installedRoot->setRequires([]); |
92
|
|
|
$installedRoot->setDevRequires([]); |
93
|
|
|
|
94
|
|
|
$this->pool = new Pool($this->package->getMinimumStability(), $this->package->getStabilityFlags()); |
95
|
|
|
$this->platform = new PlatformRepository(); |
96
|
|
|
$this->installed = new CompositeRepository( |
97
|
|
|
[ |
98
|
|
|
new InstalledArrayRepository(array($installedRoot)), |
99
|
|
|
$this->composer->getRepositoryManager()->getLocalRepository(), |
100
|
|
|
$this->platform |
101
|
|
|
] |
102
|
|
|
); |
103
|
|
|
|
104
|
|
|
$this->pool->addRepository( |
105
|
|
|
new CompositeRepository( |
106
|
|
|
array_merge([$this->installed], $this->composer->getRepositoryManager()->getRepositories()) |
107
|
|
|
) |
108
|
|
|
); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Build a new request preserving the current requires. |
113
|
|
|
* |
114
|
|
|
* @return Request |
115
|
|
|
*/ |
116
|
|
|
private function getRequest() |
117
|
|
|
{ |
118
|
|
|
$request = new Request($this->pool); |
|
|
|
|
119
|
|
|
|
120
|
|
|
$constraint = new Constraint('=', $this->package->getVersion()); |
121
|
|
|
$constraint->setPrettyString($this->package->getPrettyVersion()); |
122
|
|
|
$request->install($this->package->getName(), $constraint); |
123
|
|
|
|
124
|
|
|
$fixedPackages = $this->platform->getPackages(); |
125
|
|
|
|
126
|
|
|
// fix the version of all platform packages + additionally installed packages |
127
|
|
|
// to prevent the solver trying to remove or update those |
128
|
|
|
/** @var Link[] $provided */ |
129
|
|
|
$provided = $this->package->getProvides(); |
130
|
|
|
/** @var PackageInterface $package */ |
131
|
|
|
foreach ($fixedPackages as $package) { |
132
|
|
|
$constraint = new Constraint('=', $package->getVersion()); |
133
|
|
|
$constraint->setPrettyString($package->getPrettyVersion()); |
134
|
|
|
|
135
|
|
|
// skip platform packages that are provided by the root package |
136
|
|
|
if (($package->getRepository() !== $this->platform) |
137
|
|
|
|| !isset($provided[$package->getName()]) |
138
|
|
|
|| !$provided[$package->getName()]->getConstraint()->matches($constraint) |
139
|
|
|
) { |
140
|
|
|
$request->fix($package->getName(), $constraint); |
141
|
|
|
} |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
// add requirements |
145
|
|
|
$links = array_merge($this->package->getRequires(), $provided); |
146
|
|
|
/** @var Link $link */ |
147
|
|
|
foreach ($links as $link) { |
148
|
|
|
// FIXME: can't we also fix these here? Could be faster. |
|
|
|
|
149
|
|
|
$request->install($link->getTarget(), $link->getConstraint()); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
return $request; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Solve the current dependencies and return the tasks that will be performed. |
157
|
|
|
* |
158
|
|
|
* @return OperationInterface[] |
159
|
|
|
* |
160
|
|
|
* @throws SolverProblemsException When the dependencies can not be resolved. |
161
|
|
|
*/ |
162
|
|
|
public function solve() |
163
|
|
|
{ |
164
|
|
|
gc_collect_cycles(); |
165
|
|
|
gc_disable(); |
166
|
|
|
|
167
|
|
|
$solver = new Solver(new DefaultPolicy($this->package->getPreferStable()), $this->pool, $this->installed); |
168
|
|
|
$request = $this->getRequest(); |
169
|
|
|
$request->updateAll(); |
170
|
|
|
|
171
|
|
|
$operations = $solver->solve($request); |
172
|
|
|
|
173
|
|
|
gc_enable(); |
174
|
|
|
|
175
|
|
|
return $operations; |
176
|
|
|
} |
177
|
|
|
} |
178
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.