PluginProbe
Code Snippets / 4.0.0-beta.2
Code Snippets v4.0.0-beta.2
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
← All changes | vendor/composer/InstalledVersions.php +72 -13 3.0.0 → 4.0.0-beta.2 View file →
@@ -19,14 +19,40 @@
19 19 * This class is copied in every Composer installed project and available to all
20 20 *
21 21 * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
22 22 *
23 - * To require it's presence, you can require `composer-runtime-api ^2.0`
23 + * To require its presence, you can require `composer-runtime-api ^2.0`
24 + *
25 + * @final
24 26 */
25 27 class InstalledVersions
26 28 {
29 + /**
30 + * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
31 + * @internal
32 + */
33 + private static $selfDir = null;
34 +
35 + /**
36 + * @var mixed[]|null
37 + * @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
38 + */
27 39 private static $installed;
40 +
41 + /**
42 + * @var bool
43 + */
44 + private static $installedIsLocalDir;
45 +
46 + /**
47 + * @var bool|null
48 + */
28 49 private static $canGetVendors;
50 +
51 + /**
52 + * @var array[]
53 + * @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[]}>}>
54 + */
29 55 private static $installedByVendor = array();
30 56
31 57 /**
32 58 * Returns a list of all package names which are present, either by being installed, replaced or provided
@@ -82,9 +108,9 @@
82 108 public static function isInstalled($packageName, $includeDevRequirements = true)
83 109 {
84 110 foreach (self::getInstalled() as $installed) {
85 111 if (isset($installed['versions'][$packageName])) {
86 - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
112 + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
87 113 }
88 114 }
89 115
90 116 return false;
@@ -103,9 +129,9 @@
103 129 * @return bool
104 130 */
105 131 public static function satisfies(VersionParser $parser, $packageName, $constraint)
106 132 {
107 - $constraint = $parser->parseConstraints($constraint);
133 + $constraint = $parser->parseConstraints((string) $constraint);
108 134 $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
109 135
110 136 return $provided->matches($constraint);
111 137 }
@@ -227,9 +253,9 @@
227 253 }
228 254
229 255 /**
230 256 * @return array
231 - * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
257 + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
232 258 */
233 259 public static function getRootPackage()
234 260 {
235 261 $installed = self::getInstalled();
@@ -241,9 +267,9 @@
241 267 * Returns the raw installed.php data for custom implementations
242 268 *
243 269 * @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.
244 270 * @return array[]
245 - * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}
271 + * @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[]}>}
246 272 */
247 273 public static function getRawData()
248 274 {
249 275 @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);
@@ -264,9 +290,9 @@
264 290 /**
265 291 * Returns the raw data of all installed.php which are currently loaded for custom implementations
266 292 *
267 293 * @return array[]
268 - * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
294 + * @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[]}>}>
269 295 */
270 296 public static function getAllRawData()
271 297 {
272 298 return self::getInstalled();
@@ -287,19 +313,37 @@
287 313 *
288 314 * @param array[] $data A vendor/composer/installed.php data set
289 315 * @return void
290 316 *
291 - * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data
317 + * @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
292 318 */
293 319 public static function reload($data)
294 320 {
295 321 self::$installed = $data;
296 322 self::$installedByVendor = array();
323 +
324 + // when using reload, we disable the duplicate protection to ensure that self::$installed data is
325 + // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
326 + // so we have to assume it does not, and that may result in duplicate data being returned when listing
327 + // all installed packages for example
328 + self::$installedIsLocalDir = false;
297 329 }
298 330
299 331 /**
332 + * @return string
333 + */
334 + private static function getSelfDir()
335 + {
336 + if (self::$selfDir === null) {
337 + self::$selfDir = strtr(__DIR__, '\\', '/');
338 + }
339 +
340 + return self::$selfDir;
341 + }
342 +
343 + /**
300 344 * @return array[]
301 - * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
345 + * @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[]}>}>
302 346 */
303 347 private static function getInstalled()
304 348 {
305 349 if (null === self::$canGetVendors) {
@@ -306,19 +350,29 @@
306 350 self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
307 351 }
308 352
309 353 $installed = array();
354 + $copiedLocalDir = false;
310 355
311 356 if (self::$canGetVendors) {
357 + $selfDir = self::getSelfDir();
312 358 foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
359 + $vendorDir = strtr($vendorDir, '\\', '/');
313 360 if (isset(self::$installedByVendor[$vendorDir])) {
314 361 $installed[] = self::$installedByVendor[$vendorDir];
315 362 } elseif (is_file($vendorDir.'/composer/installed.php')) {
316 - $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
317 - if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
318 - self::$installed = $installed[count($installed) - 1];
363 + /** @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 */
364 + $required = require $vendorDir.'/composer/installed.php';
365 + self::$installedByVendor[$vendorDir] = $required;
366 + $installed[] = $required;
367 + if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
368 + self::$installed = $required;
369 + self::$installedIsLocalDir = true;
319 370 }
320 371 }
372 + if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
373 + $copiedLocalDir = true;
374 + }
321 375 }
322 376 }
323 377
324 378 if (null === self::$installed) {
@@ -324,14 +378,19 @@
324 378 if (null === self::$installed) {
325 379 // only require the installed.php file if this file is loaded from its dumped location,
326 380 // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
327 381 if (substr(__DIR__, -8, 1) !== 'C') {
328 - self::$installed = require __DIR__ . '/installed.php';
382 + /** @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 */
383 + $required = require __DIR__ . '/installed.php';
384 + self::$installed = $required;
329 385 } else {
330 386 self::$installed = array();
331 387 }
332 388 }
333 - $installed[] = self::$installed;
389 +
390 + if (self::$installed !== array() && !$copiedLocalDir) {
391 + $installed[] = self::$installed;
392 + }
334 393
335 394 return $installed;
336 395 }
337 396 }