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