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