diff options
Diffstat (limited to 'vendor/composer/InstalledVersions.php')
-rw-r--r-- | vendor/composer/InstalledVersions.php | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..51e734a --- /dev/null +++ b/vendor/composer/InstalledVersions.php | |||
@@ -0,0 +1,359 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Composer. | ||
5 | * | ||
6 | * (c) Nils Adermann <naderman@naderman.de> | ||
7 | * Jordi Boggiano <j.boggiano@seld.be> | ||
8 | * | ||
9 | * For the full copyright and license information, please view the LICENSE | ||
10 | * file that was distributed with this source code. | ||
11 | */ | ||
12 | |||
13 | namespace Composer; | ||
14 | |||
15 | use Composer\Autoload\ClassLoader; | ||
16 | use Composer\Semver\VersionParser; | ||
17 | |||
18 | /** | ||
19 | * This class is copied in every Composer installed project and available to all | ||
20 | * | ||
21 | * See also https://getcomposer.org/doc/07-runtime.md#installed-versions | ||
22 | * | ||
23 | * To require its presence, you can require `composer-runtime-api ^2.0` | ||
24 | * | ||
25 | * @final | ||
26 | */ | ||
27 | class InstalledVersions | ||
28 | { | ||
29 | /** | ||
30 | * @var mixed[]|null | ||
31 | * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null | ||
32 | */ | ||
33 | private static $installed; | ||
34 | |||
35 | /** | ||
36 | * @var bool|null | ||
37 | */ | ||
38 | private static $canGetVendors; | ||
39 | |||
40 | /** | ||
41 | * @var array[] | ||
42 | * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> | ||
43 | */ | ||
44 | private static $installedByVendor = array(); | ||
45 | |||
46 | /** | ||
47 | * Returns a list of all package names which are present, either by being installed, replaced or provided | ||
48 | * | ||
49 | * @return string[] | ||
50 | * @psalm-return list<string> | ||
51 | */ | ||
52 | public static function getInstalledPackages() | ||
53 | { | ||
54 | $packages = array(); | ||
55 | foreach (self::getInstalled() as $installed) { | ||
56 | $packages[] = array_keys($installed['versions']); | ||
57 | } | ||
58 | |||
59 | if (1 === \count($packages)) { | ||
60 | return $packages[0]; | ||
61 | } | ||
62 | |||
63 | return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * Returns a list of all package names with a specific type e.g. 'library' | ||
68 | * | ||
69 | * @param string $type | ||
70 | * @return string[] | ||
71 | * @psalm-return list<string> | ||
72 | */ | ||
73 | public static function getInstalledPackagesByType($type) | ||
74 | { | ||
75 | $packagesByType = array(); | ||
76 | |||
77 | foreach (self::getInstalled() as $installed) { | ||
78 | foreach ($installed['versions'] as $name => $package) { | ||
79 | if (isset($package['type']) && $package['type'] === $type) { | ||
80 | $packagesByType[] = $name; | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | |||
85 | return $packagesByType; | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | * Checks whether the given package is installed | ||
90 | * | ||
91 | * This also returns true if the package name is provided or replaced by another package | ||
92 | * | ||
93 | * @param string $packageName | ||
94 | * @param bool $includeDevRequirements | ||
95 | * @return bool | ||
96 | */ | ||
97 | public static function isInstalled($packageName, $includeDevRequirements = true) | ||
98 | { | ||
99 | foreach (self::getInstalled() as $installed) { | ||
100 | if (isset($installed['versions'][$packageName])) { | ||
101 | return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | return false; | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * Checks whether the given package satisfies a version constraint | ||
110 | * | ||
111 | * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: | ||
112 | * | ||
113 | * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') | ||
114 | * | ||
115 | * @param VersionParser $parser Install composer/semver to have access to this class and functionality | ||
116 | * @param string $packageName | ||
117 | * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package | ||
118 | * @return bool | ||
119 | */ | ||
120 | public static function satisfies(VersionParser $parser, $packageName, $constraint) | ||
121 | { | ||
122 | $constraint = $parser->parseConstraints((string) $constraint); | ||
123 | $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); | ||
124 | |||
125 | return $provided->matches($constraint); | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * Returns a version constraint representing all the range(s) which are installed for a given package | ||
130 | * | ||
131 | * It is easier to use this via isInstalled() with the $constraint argument if you need to check | ||
132 | * whether a given version of a package is installed, and not just whether it exists | ||
133 | * | ||
134 | * @param string $packageName | ||
135 | * @return string Version constraint usable with composer/semver | ||
136 | */ | ||
137 | public static function getVersionRanges($packageName) | ||
138 | { | ||
139 | foreach (self::getInstalled() as $installed) { | ||
140 | if (!isset($installed['versions'][$packageName])) { | ||
141 | continue; | ||
142 | } | ||
143 | |||
144 | $ranges = array(); | ||
145 | if (isset($installed['versions'][$packageName]['pretty_version'])) { | ||
146 | $ranges[] = $installed['versions'][$packageName]['pretty_version']; | ||
147 | } | ||
148 | if (array_key_exists('aliases', $installed['versions'][$packageName])) { | ||
149 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); | ||
150 | } | ||
151 | if (array_key_exists('replaced', $installed['versions'][$packageName])) { | ||
152 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); | ||
153 | } | ||
154 | if (array_key_exists('provided', $installed['versions'][$packageName])) { | ||
155 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); | ||
156 | } | ||
157 | |||
158 | return implode(' || ', $ranges); | ||
159 | } | ||
160 | |||
161 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * @param string $packageName | ||
166 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present | ||
167 | */ | ||
168 | public static function getVersion($packageName) | ||
169 | { | ||
170 | foreach (self::getInstalled() as $installed) { | ||
171 | if (!isset($installed['versions'][$packageName])) { | ||
172 | continue; | ||
173 | } | ||
174 | |||
175 | if (!isset($installed['versions'][$packageName]['version'])) { | ||
176 | return null; | ||
177 | } | ||
178 | |||
179 | return $installed['versions'][$packageName]['version']; | ||
180 | } | ||
181 | |||
182 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * @param string $packageName | ||
187 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present | ||
188 | */ | ||
189 | public static function getPrettyVersion($packageName) | ||
190 | { | ||
191 | foreach (self::getInstalled() as $installed) { | ||
192 | if (!isset($installed['versions'][$packageName])) { | ||
193 | continue; | ||
194 | } | ||
195 | |||
196 | if (!isset($installed['versions'][$packageName]['pretty_version'])) { | ||
197 | return null; | ||
198 | } | ||
199 | |||
200 | return $installed['versions'][$packageName]['pretty_version']; | ||
201 | } | ||
202 | |||
203 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * @param string $packageName | ||
208 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference | ||
209 | */ | ||
210 | public static function getReference($packageName) | ||
211 | { | ||
212 | foreach (self::getInstalled() as $installed) { | ||
213 | if (!isset($installed['versions'][$packageName])) { | ||
214 | continue; | ||
215 | } | ||
216 | |||
217 | if (!isset($installed['versions'][$packageName]['reference'])) { | ||
218 | return null; | ||
219 | } | ||
220 | |||
221 | return $installed['versions'][$packageName]['reference']; | ||
222 | } | ||
223 | |||
224 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * @param string $packageName | ||
229 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. | ||
230 | */ | ||
231 | public static function getInstallPath($packageName) | ||
232 | { | ||
233 | foreach (self::getInstalled() as $installed) { | ||
234 | if (!isset($installed['versions'][$packageName])) { | ||
235 | continue; | ||
236 | } | ||
237 | |||
238 | return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; | ||
239 | } | ||
240 | |||
241 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * @return array | ||
246 | * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} | ||
247 | */ | ||
248 | public static function getRootPackage() | ||
249 | { | ||
250 | $installed = self::getInstalled(); | ||
251 | |||
252 | return $installed[0]['root']; | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * Returns the raw installed.php data for custom implementations | ||
257 | * | ||
258 | * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. | ||
259 | * @return array[] | ||
260 | * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} | ||
261 | */ | ||
262 | public static function getRawData() | ||
263 | { | ||
264 | @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); | ||
265 | |||
266 | if (null === self::$installed) { | ||
267 | // only require the installed.php file if this file is loaded from its dumped location, | ||
268 | // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 | ||
269 | if (substr(__DIR__, -8, 1) !== 'C') { | ||
270 | self::$installed = include __DIR__ . '/installed.php'; | ||
271 | } else { | ||
272 | self::$installed = array(); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | return self::$installed; | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * Returns the raw data of all installed.php which are currently loaded for custom implementations | ||
281 | * | ||
282 | * @return array[] | ||
283 | * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> | ||
284 | */ | ||
285 | public static function getAllRawData() | ||
286 | { | ||
287 | return self::getInstalled(); | ||
288 | } | ||
289 | |||
290 | /** | ||
291 | * Lets you reload the static array from another file | ||
292 | * | ||
293 | * This is only useful for complex integrations in which a project needs to use | ||
294 | * this class but then also needs to execute another project's autoloader in process, | ||
295 | * and wants to ensure both projects have access to their version of installed.php. | ||
296 | * | ||
297 | * A typical case would be PHPUnit, where it would need to make sure it reads all | ||
298 | * the data it needs from this class, then call reload() with | ||
299 | * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure | ||
300 | * the project in which it runs can then also use this class safely, without | ||
301 | * interference between PHPUnit's dependencies and the project's dependencies. | ||
302 | * | ||
303 | * @param array[] $data A vendor/composer/installed.php data set | ||
304 | * @return void | ||
305 | * | ||
306 | * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data | ||
307 | */ | ||
308 | public static function reload($data) | ||
309 | { | ||
310 | self::$installed = $data; | ||
311 | self::$installedByVendor = array(); | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * @return array[] | ||
316 | * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> | ||
317 | */ | ||
318 | private static function getInstalled() | ||
319 | { | ||
320 | if (null === self::$canGetVendors) { | ||
321 | self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); | ||
322 | } | ||
323 | |||
324 | $installed = array(); | ||
325 | |||
326 | if (self::$canGetVendors) { | ||
327 | foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { | ||
328 | if (isset(self::$installedByVendor[$vendorDir])) { | ||
329 | $installed[] = self::$installedByVendor[$vendorDir]; | ||
330 | } elseif (is_file($vendorDir.'/composer/installed.php')) { | ||
331 | /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ | ||
332 | $required = require $vendorDir.'/composer/installed.php'; | ||
333 | $installed[] = self::$installedByVendor[$vendorDir] = $required; | ||
334 | if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { | ||
335 | self::$installed = $installed[count($installed) - 1]; | ||
336 | } | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | |||
341 | if (null === self::$installed) { | ||
342 | // only require the installed.php file if this file is loaded from its dumped location, | ||
343 | // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 | ||
344 | if (substr(__DIR__, -8, 1) !== 'C') { | ||
345 | /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ | ||
346 | $required = require __DIR__ . '/installed.php'; | ||
347 | self::$installed = $required; | ||
348 | } else { | ||
349 | self::$installed = array(); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | if (self::$installed !== array()) { | ||
354 | $installed[] = self::$installed; | ||
355 | } | ||
356 | |||
357 | return $installed; | ||
358 | } | ||
359 | } | ||